diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/hir_typeck/expr_cs.cpp | 31 | ||||
-rw-r--r-- | src/hir_typeck/helpers.cpp | 59 | ||||
-rw-r--r-- | src/hir_typeck/helpers.hpp | 10 |
3 files changed, 78 insertions, 22 deletions
diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 32cdf7bb..9d412cba 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -1163,9 +1163,14 @@ namespace { continue ; if( !it->second.is_Function() ) continue ; - possible_traits.push_back( trait_ref ); - if( trait_ref.second->m_params.m_types.size() > max_num_params ) - max_num_params = trait_ref.second->m_params.m_types.size(); + + if( ::std::count_if( possible_traits.begin(), possible_traits.end(), [&](const auto&x){return x.second == trait_ref.second;}) ) { + } + else { + possible_traits.push_back( trait_ref ); + if( trait_ref.second->m_params.m_types.size() > max_num_params ) + max_num_params = trait_ref.second->m_params.m_types.size(); + } } // > Store the possible set of traits for later node.m_traits = mv$(possible_traits); @@ -2142,8 +2147,26 @@ namespace { this->context.equate_types(sp, node.m_res_type, node.m_cache.m_arg_types.back()); // Add derefs - if( deref_count > 0 ) + if( deref_count >= ~3u ) + { + ::HIR::BorrowType bt = ::HIR::BorrowType::Shared; + switch(deref_count) + { + case ~1u: bt = ::HIR::BorrowType::Shared; break; + case ~2u: bt = ::HIR::BorrowType::Unique; break; + case ~3u: bt = ::HIR::BorrowType::Owned ; break; + default: + BUG(sp, "Invalid deref return count - " << deref_count); + } + + auto ty = ::HIR::TypeRef::new_borrow(bt, node.m_value->m_res_type.clone()); + DEBUG("- Ref " << &*node.m_value << " -> " << ty); + auto span = node.m_value->span(); + node.m_value = NEWNODE(mv$(ty), span, _Borrow, bt, mv$(node.m_value) ); + } + else if( deref_count > 0 ) { + assert( deref_count < (1<<16) ); // Just some sanity. DEBUG("- Inserting " << deref_count << " dereferences"); // Get dereferencing! auto& node_ptr = node.m_value; diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 64a12801..e9276601 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -2259,7 +2259,8 @@ unsigned int TraitResolution::autoderef_find_method(const Span& sp, const HIR::t return ~0u; } - if( this->find_method(sp, traits, ivars, ty, method_name, unconditional_allow_move || (deref_count == 0), fcn_path) ) { + auto allowed_receivers = (unconditional_allow_move || (deref_count == 0) ? AllowedReceivers::All : AllowedReceivers::AnyBorrow); + if( this->find_method(sp, traits, ivars, ty, method_name, allowed_receivers, fcn_path) ) { DEBUG("FOUND " << deref_count << ", fcn_path = " << fcn_path); return deref_count; } @@ -2273,25 +2274,47 @@ unsigned int TraitResolution::autoderef_find_method(const Span& sp, const HIR::t TU_IFLET(::HIR::TypeRef::Data, top_ty_r.m_data, Borrow, e, const auto& ty = top_ty_r; - if( find_method(sp, traits, ivars, ty, method_name, true, fcn_path) ) { + if( find_method(sp, traits, ivars, ty, method_name, AllowedReceivers::All, fcn_path) ) { DEBUG("FOUND " << 0 << ", fcn_path = " << fcn_path); return 0; } ) - // Dereference failed! This is a hard error (hitting _ is checked above and returns ~0) + // If there are ivars within the type, don't error (yet) if( this->m_ivars.type_contains_ivars(top_ty) ) { return ~0u; } - else - { - this->m_ivars.dump(); - ERROR(sp, E0000, "Could not find method `" << method_name << "` on type `" << top_ty << "`"); + + // TODO: Insert a single reference and try again (only allowing by-value methods), returning a magic value (e.g. ~1u) + // - Required for calling `(self[..]: str).into_searcher(haystack)` - Which invokes `<&str as Pattern>::into_searcher(&self[..], haystack)` + // - Have to do several tries, each with different borrow classes. + auto borrow_ty = ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, top_ty.clone()); + if( find_method(sp, traits, ivars, borrow_ty, method_name, AllowedReceivers::Value, fcn_path) ) { + DEBUG("FOUND &, fcn_path = " << fcn_path); + return ~1u; } + borrow_ty.m_data.as_Borrow().type = ::HIR::BorrowType::Unique; + if( find_method(sp, traits, ivars, borrow_ty, method_name, AllowedReceivers::Value, fcn_path) ) { + DEBUG("FOUND &mut, fcn_path = " << fcn_path); + return ~2u; + } + borrow_ty.m_data.as_Borrow().type = ::HIR::BorrowType::Owned; + if( find_method(sp, traits, ivars, borrow_ty, method_name, AllowedReceivers::Value, fcn_path) ) { + DEBUG("FOUND &mut, fcn_path = " << fcn_path); + return ~2u; + } + + // Dereference failed! This is a hard error (hitting _ is checked above and returns ~0) + this->m_ivars.dump(); + ERROR(sp, E0000, "Could not find method `" << method_name << "` on type `" << top_ty << "`"); } -bool TraitResolution::find_method(const Span& sp, const HIR::t_trait_list& traits, const ::std::vector<unsigned>& ivars, const ::HIR::TypeRef& ty, const ::std::string& method_name, bool allow_move, /* Out -> */::HIR::Path& fcn_path) const +bool TraitResolution::find_method( + const Span& sp, + const HIR::t_trait_list& traits, const ::std::vector<unsigned>& ivars, + const ::HIR::TypeRef& ty, const ::std::string& method_name, AllowedReceivers ar, + /* Out -> */::HIR::Path& fcn_path) const { TRACE_FUNCTION_F("ty=" << ty << ", name=" << method_name); // 1. Search generic bounds for a match @@ -2310,7 +2333,7 @@ bool TraitResolution::find_method(const Span& sp, const HIR::t_trait_list& trait DEBUG("Bound `" << e.type << " : " << e.trait.m_path << "` - Matches " << ty); ::HIR::GenericPath final_trait_path; assert(e.trait.m_trait_ptr); - if( !this->trait_contains_method(sp, e.trait.m_path, *e.trait.m_trait_ptr, method_name, allow_move, final_trait_path) ) + if( !this->trait_contains_method(sp, e.trait.m_path, *e.trait.m_trait_ptr, method_name, ar != AllowedReceivers::AnyBorrow, final_trait_path) ) continue ; DEBUG("- Found trait " << final_trait_path); @@ -2342,7 +2365,7 @@ bool TraitResolution::find_method(const Span& sp, const HIR::t_trait_list& trait break; case ::HIR::Function::Receiver::Value: // Only accept by-value methods if not dereferencing to them - if( !allow_move ) + if( ar == AllowedReceivers::AnyBorrow ) break; default: fcn_path = ::HIR::Path( ::HIR::Path::Data::Data_UfcsKnown({ @@ -2372,7 +2395,7 @@ bool TraitResolution::find_method(const Span& sp, const HIR::t_trait_list& trait { ASSERT_BUG(sp, bound.m_trait_ptr, "Pointer to trait " << bound.m_path << " not set in " << e.trait.m_path); ::HIR::GenericPath final_trait_path; - if( !this->trait_contains_method(sp, bound.m_path, *bound.m_trait_ptr, method_name, allow_move, final_trait_path) ) + if( !this->trait_contains_method(sp, bound.m_path, *bound.m_trait_ptr, method_name, ar != AllowedReceivers::AnyBorrow, final_trait_path) ) continue ; DEBUG("- Found trait " << final_trait_path); @@ -2421,9 +2444,12 @@ bool TraitResolution::find_method(const Span& sp, const HIR::t_trait_list& trait case ::HIR::Function::Receiver::Free: break; case ::HIR::Function::Receiver::Value: - if( !allow_move ) + if( ar == AllowedReceivers::AnyBorrow ) break; + if( 0 ) default: + if( ar == AllowedReceivers::Value ) + break; DEBUG("Matching `impl" << impl.m_params.fmt_args() << " " << impl.m_type << "`"/* << " - " << top_ty*/); fcn_path = ::HIR::Path( ::HIR::Path::Data::make_UfcsInherent({ box$(ty.clone()), @@ -2462,14 +2488,15 @@ bool TraitResolution::find_method(const Span& sp, const HIR::t_trait_list& trait case ::HIR::Function::Receiver::Free: break; case ::HIR::Function::Receiver::Value: - if( !allow_move ) + if( ar == AllowedReceivers::AnyBorrow ) break; if(0) - case ::HIR::Function::Receiver::Box: + default: + if( ar == AllowedReceivers::Value ) + break; // NOTE: Only allow picking a `self: Box<Self>` method if we've been through a deref. - if( allow_move ) + if( v.m_receiver == ::HIR::Function::Receiver::Box && ar != AllowedReceivers::AnyBorrow ) break; - default: DEBUG("Search for impl of " << *trait_ref.first); // Use the set of ivars we were given to populate the trait parameters diff --git a/src/hir_typeck/helpers.hpp b/src/hir_typeck/helpers.hpp index ea85adfc..c44520fc 100644 --- a/src/hir_typeck/helpers.hpp +++ b/src/hir_typeck/helpers.hpp @@ -217,9 +217,15 @@ public: /// Apply an automatic dereference const ::HIR::TypeRef* autoderef(const Span& sp, const ::HIR::TypeRef& ty, ::HIR::TypeRef& tmp_type) const; - + bool find_field(const Span& sp, const ::HIR::TypeRef& ty, const ::std::string& name, /* Out -> */::HIR::TypeRef& field_type) const; - bool find_method(const Span& sp, const HIR::t_trait_list& traits, const ::std::vector<unsigned>& ivars, const ::HIR::TypeRef& ty, const ::std::string& method_name, bool allow_move, /* Out -> */::HIR::Path& fcn_path) const; + + enum class AllowedReceivers { + All, + AnyBorrow, + Value, + }; + bool find_method(const Span& sp, const HIR::t_trait_list& traits, const ::std::vector<unsigned>& ivars, const ::HIR::TypeRef& ty, const ::std::string& method_name, AllowedReceivers ar, /* Out -> */::HIR::Path& fcn_path) const; /// Locates a named method in a trait, and returns the path of the trait that contains it (with fixed parameters) bool trait_contains_method(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::std::string& name, bool allow_move, ::HIR::GenericPath& out_path) const; |