diff options
author | John Hodge <tpg@mutabah.net> | 2016-06-11 09:25:30 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2016-06-11 09:25:30 +0800 |
commit | 2da4fb9a180be57e396278bb0a7fa9eb1adc65f9 (patch) | |
tree | 3ef38a52b2694d351b355f0b403067b2d4ea40a6 | |
parent | 436dad1104d40270d6b6a805b412d4603f27249c (diff) | |
download | mrust-2da4fb9a180be57e396278bb0a7fa9eb1adc65f9.tar.gz |
HIR Typecheck - Search methods inside &-ptrs before on the &-ptr
-rw-r--r-- | src/hir_typeck/expr.hpp | 1 | ||||
-rw-r--r-- | src/hir_typeck/expr_context.cpp | 230 |
2 files changed, 129 insertions, 102 deletions
diff --git a/src/hir_typeck/expr.hpp b/src/hir_typeck/expr.hpp index 309b7965..adf60c67 100644 --- a/src/hir_typeck/expr.hpp +++ b/src/hir_typeck/expr.hpp @@ -139,6 +139,7 @@ public: /// Locate the named method by applying auto-dereferencing. /// \return Number of times deref was applied (or ~0 if _ was hit) unsigned int autoderef_find_method(const Span& sp, const ::HIR::TypeRef& top_ty, const ::std::string& method_name, /* Out -> */::HIR::Path& fcn_path) const; + bool find_method(const Span& sp, const ::HIR::TypeRef& ty, const ::std::string& method_name, /* Out -> */::HIR::Path& fcn_path) const; public: ::std::function<const ::HIR::TypeRef&(const ::HIR::TypeRef&)> callback_resolve_infer() { diff --git a/src/hir_typeck/expr_context.cpp b/src/hir_typeck/expr_context.cpp index d69642c9..df1300a7 100644 --- a/src/hir_typeck/expr_context.cpp +++ b/src/hir_typeck/expr_context.cpp @@ -1347,114 +1347,19 @@ unsigned int typeck::TypecheckContext::autoderef_find_method(const Span& sp, con { unsigned int deref_count = 0; const auto* current_ty = &top_ty; + TU_IFLET(::HIR::TypeRef::Data, this->get_type(top_ty).m_data, Borrow, e, + current_ty = &*e.inner; + deref_count += 1; + ) + do { const auto& ty = this->get_type(*current_ty); if( ty.m_data.is_Infer() ) { return ~0u; } - // 1. Search generic bounds for a match - const ::HIR::GenericParams* v[2] = { m_item_params, m_impl_params }; - for(auto p : v) - { - if( !p ) continue ; - for(const auto& b : p->m_bounds) - { - TU_IFLET(::HIR::GenericBound, b, TraitBound, e, - DEBUG("Bound " << e.type << " : " << e.trait.m_path); - // TODO: Match using _ replacement - if( e.type != ty ) - continue ; - - // - Bound's type matches, check if the bounded trait has the method we're searching for - // > TODO: Search supertraits too - DEBUG("- 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, final_trait_path) ) - continue ; - DEBUG("- Found trait " << final_trait_path); - - // Found the method, return the UFCS path for it - fcn_path = ::HIR::Path( ::HIR::Path::Data::make_UfcsKnown({ - box$( ty.clone() ), - mv$(final_trait_path), - method_name, - {} - }) ); - return deref_count; - ) - } - } - - TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Generic, e, - // No match, keep trying. - ) - else if( ty.m_data.is_Path() && ty.m_data.as_Path().path.m_data.is_UfcsKnown() ) - { - const auto& e = ty.m_data.as_Path().path.m_data.as_UfcsKnown(); - // UFCS known - Assuming that it's reached the maximum resolvable level (i.e. a type within is generic), search for trait bounds on the type - const auto& trait = this->m_crate.get_trait_by_path(sp, e.trait.m_path); - const auto& assoc_ty = trait.m_types.at( e.item ); - // NOTE: The bounds here have 'Self' = the type - for(const auto& bound : assoc_ty.m_params.m_bounds ) - { - TU_IFLET(::HIR::GenericBound, bound, TraitBound, be, - assert(be.trait.m_trait_ptr); - ::HIR::GenericPath final_trait_path; - if( !this->trait_contains_method(sp, be.trait.m_path, *be.trait.m_trait_ptr, method_name, final_trait_path) ) - continue ; - DEBUG("- Found trait " << final_trait_path); - - // Found the method, return the UFCS path for it - fcn_path = ::HIR::Path( ::HIR::Path::Data::make_UfcsKnown({ - box$( ty.clone() ), - mv$(final_trait_path), - method_name, - {} - }) ); - return deref_count; - ) - } - } - else { - // 2. Search for inherent methods - for(const auto& impl : m_crate.m_type_impls) - { - if( impl.matches_type(ty) ) { - auto it = impl.m_methods.find( method_name ); - if( it == impl.m_methods.end() ) - continue ; - 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()), - method_name, - {} - }) ); - return deref_count; - } - } - // 3. Search for trait methods (using currently in-scope traits) - for(const auto& trait_ref : ::reverse(m_traits)) - { - // TODO: Search supertraits too - auto it = trait_ref.second->m_values.find(method_name); - if( it == trait_ref.second->m_values.end() ) - continue ; - if( !it->second.is_Function() ) - continue ; - DEBUG("Search for impl of " << *trait_ref.first); - if( find_trait_impls_crate(*trait_ref.first, ty, [](const auto&) { return true; }) ) { - DEBUG("Found trait impl " << *trait_ref.first << " for " << ty); - fcn_path = ::HIR::Path( ::HIR::Path::Data::make_UfcsKnown({ - box$( ty.clone() ), - trait_ref.first->clone(), - method_name, - {} - }) ); - return deref_count; - } - } + if( find_method(sp, ty, method_name, fcn_path) ) { + return deref_count; } // 3. Dereference and try again @@ -1467,11 +1372,132 @@ unsigned int typeck::TypecheckContext::autoderef_find_method(const Span& sp, con current_ty = nullptr; } } while( current_ty ); + + TU_IFLET(::HIR::TypeRef::Data, this->get_type(top_ty).m_data, Borrow, e, + const auto& ty = this->get_type(top_ty); + + if( find_method(sp, ty, method_name, fcn_path) ) { + return 0; + } + ) + // Dereference failed! This is a hard error (hitting _ is checked above and returns ~0) this->dump(); TODO(sp, "Error when no method could be found, but type is known - (: " << top_ty << ")." << method_name); } +bool typeck::TypecheckContext::find_method(const Span& sp, const ::HIR::TypeRef& ty, const ::std::string& method_name, /* Out -> */::HIR::Path& fcn_path) const +{ + // 1. Search generic bounds for a match + const ::HIR::GenericParams* v[2] = { m_item_params, m_impl_params }; + for(auto p : v) + { + if( !p ) continue ; + for(const auto& b : p->m_bounds) + { + TU_IFLET(::HIR::GenericBound, b, TraitBound, e, + DEBUG("Bound " << e.type << " : " << e.trait.m_path); + // TODO: Match using _ replacement + if( e.type != ty ) + continue ; + + // - Bound's type matches, check if the bounded trait has the method we're searching for + // > TODO: Search supertraits too + DEBUG("- 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, final_trait_path) ) + continue ; + DEBUG("- Found trait " << final_trait_path); + + // Found the method, return the UFCS path for it + fcn_path = ::HIR::Path( ::HIR::Path::Data::make_UfcsKnown({ + box$( ty.clone() ), + mv$(final_trait_path), + method_name, + {} + }) ); + return true; + ) + } + } + + TU_IFLET(::HIR::TypeRef::Data, ty.m_data, TraitObject, e, + // TODO: Search methods on object's traits + ) + + TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Generic, e, + // No match, keep trying. + ) + else if( ty.m_data.is_Path() && ty.m_data.as_Path().path.m_data.is_UfcsKnown() ) + { + const auto& e = ty.m_data.as_Path().path.m_data.as_UfcsKnown(); + // UFCS known - Assuming that it's reached the maximum resolvable level (i.e. a type within is generic), search for trait bounds on the type + const auto& trait = this->m_crate.get_trait_by_path(sp, e.trait.m_path); + const auto& assoc_ty = trait.m_types.at( e.item ); + // NOTE: The bounds here have 'Self' = the type + for(const auto& bound : assoc_ty.m_params.m_bounds ) + { + TU_IFLET(::HIR::GenericBound, bound, TraitBound, be, + assert(be.trait.m_trait_ptr); + ::HIR::GenericPath final_trait_path; + if( !this->trait_contains_method(sp, be.trait.m_path, *be.trait.m_trait_ptr, method_name, final_trait_path) ) + continue ; + DEBUG("- Found trait " << final_trait_path); + + // Found the method, return the UFCS path for it + fcn_path = ::HIR::Path( ::HIR::Path::Data::make_UfcsKnown({ + box$( ty.clone() ), + mv$(final_trait_path), + method_name, + {} + }) ); + return true; + ) + } + } + else { + // 2. Search for inherent methods + for(const auto& impl : m_crate.m_type_impls) + { + if( impl.matches_type(ty) ) { + auto it = impl.m_methods.find( method_name ); + if( it == impl.m_methods.end() ) + continue ; + 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()), + method_name, + {} + }) ); + return true; + } + } + // 3. Search for trait methods (using currently in-scope traits) + for(const auto& trait_ref : ::reverse(m_traits)) + { + // TODO: Search supertraits too + auto it = trait_ref.second->m_values.find(method_name); + if( it == trait_ref.second->m_values.end() ) + continue ; + if( !it->second.is_Function() ) + continue ; + DEBUG("Search for impl of " << *trait_ref.first); + if( find_trait_impls_crate(*trait_ref.first, ty, [](const auto&) { return true; }) ) { + DEBUG("Found trait impl " << *trait_ref.first << " for " << ty); + fcn_path = ::HIR::Path( ::HIR::Path::Data::make_UfcsKnown({ + box$( ty.clone() ), + trait_ref.first->clone(), + method_name, + {} + }) ); + return true; + } + } + } + + return false; +} |