diff options
author | John Hodge <tpg@mutabah.net> | 2016-09-24 11:54:53 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2016-09-24 11:54:53 +0800 |
commit | 9f05fd7ffc8908ea5c266c40ec11a812fc6309d4 (patch) | |
tree | 438eb07c9ce0676d81fc18d86e71e63c38cbcc99 /src | |
parent | b236bbfb13db816666803778b79c22784088efb3 (diff) | |
download | mrust-9f05fd7ffc8908ea5c266c40ec11a812fc6309d4.tar.gz |
HIR Typecheck Expr - Provide a list of usable ivars to find_method
Diffstat (limited to 'src')
-rw-r--r-- | src/hir/expr.hpp | 5 | ||||
-rw-r--r-- | src/hir_typeck/expr_cs.cpp | 31 | ||||
-rw-r--r-- | src/hir_typeck/helpers.cpp | 41 | ||||
-rw-r--r-- | src/hir_typeck/helpers.hpp | 4 |
4 files changed, 60 insertions, 21 deletions
diff --git a/src/hir/expr.hpp b/src/hir/expr.hpp index ba1066b9..0903ca5a 100644 --- a/src/hir/expr.hpp +++ b/src/hir/expr.hpp @@ -511,8 +511,13 @@ struct ExprNode_CallMethod: // - Set during typeck to the real path to the method ::HIR::Path m_method_path; + // - Cache of argument/return types ExprCallCache m_cache; + + // - List of possible traits (in-scope traits that contain this method) t_trait_list m_traits; + // - A pool of ivars to use for searching for trait impls + ::std::vector<unsigned int> m_trait_param_ivars; ExprNode_CallMethod(Span sp, ::HIR::ExprNodeP val, ::std::string method_name, ::HIR::PathParams params, ::std::vector< ::HIR::ExprNodeP> args): ExprNode( mv$(sp) ), diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 2f02c722..d2b369dd 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -1151,6 +1151,7 @@ namespace { // - Search in-scope trait list for traits that provide a method of this name const ::std::string& method_name = node.m_method; ::HIR::t_trait_list possible_traits; + unsigned int max_num_params = 0; for(const auto& trait_ref : ::reverse(m_traits)) { if( trait_ref.first == nullptr ) @@ -1163,9 +1164,15 @@ namespace { 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(); } // > Store the possible set of traits for later node.m_traits = mv$(possible_traits); + for(unsigned int i = 0; i < max_num_params; i ++) + { + node.m_trait_param_ivars.push_back( this->context.m_ivars.new_ivar() ); + } // Resolution can't be done until lefthand type is known. // > Has to be done during iteraton @@ -2089,7 +2096,7 @@ namespace { // Using autoderef, locate this method on the type ::HIR::Path fcn_path { ::HIR::SimplePath() }; - unsigned int deref_count = this->context.m_resolve.autoderef_find_method(node.span(), node.m_traits, ty, node.m_method, fcn_path); + unsigned int deref_count = this->context.m_resolve.autoderef_find_method(node.span(), node.m_traits, node.m_trait_param_ivars, ty, node.m_method, fcn_path); if( deref_count != ~0u ) { DEBUG("- deref_count = " << deref_count << ", fcn_path = " << fcn_path); @@ -2177,13 +2184,29 @@ namespace { } break; case ::HIR::Function::Receiver::Box: { // - Undo a deref (there must have been one?) and ensure that it leads to a Box<Self> + // NOTE: Doesn't check deref_count, because this could have been calld as `(*somebox).method()` auto* deref_ptr = dynamic_cast< ::HIR::ExprNode_Deref*>(&*node_ptr); ASSERT_BUG(sp, deref_ptr != nullptr, "Calling Box receiver method but no deref happened"); node_ptr = mv$(deref_ptr->m_value); DEBUG("- Undo deref " << deref_ptr << " -> " << node_ptr->m_res_type); - // TODO: Triple-check that the input to the above Deref was a Box (lang="owned_box") - //TU_IFLET(::HIR::TypeRef::Data, node_ptr->m_res_type.m_data, Path, e, - //) + + // Triple-check that the input to the above Deref was a Box (lang="owned_box") + const auto& box_ty = this->context.get_type(node_ptr->m_res_type); + TU_IFLET(::HIR::TypeRef::Data, box_ty.m_data, Path, e, + TU_IFLET(::HIR::Path::Data, e.path.m_data, Generic, pe, + if( pe.m_path == this->context.m_crate.get_lang_item_path(sp, "owned_box") ) { + } + else { + ERROR(sp, E0000, "Calling Box receiver method on non-box - " << box_ty); + } + ) + else { + ERROR(sp, E0000, "Calling Box receiver method on non-box - " << box_ty); + } + ) + else { + ERROR(sp, E0000, "Calling Box receiver method on non-box - " << box_ty); + } } break; } } diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index 42430a6d..4e2bde2c 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -901,6 +901,8 @@ void TraitResolution::prep_indexes() ASSERT_BUG( sp, left.m_types.size() == right.m_types.size(), "Parameter count mismatch" ); ::HIR::Compare ord = ::HIR::Compare::Equal; for(unsigned int i = 0; i < left.m_types.size(); i ++) { + // TODO: Should allow fuzzy matches using placeholders (match_test_generics_fuzz works for that) + // - Better solution is to remove the placeholders in method searching. ord &= left.m_types[i].compare_with_placeholders(sp, right.m_types[i], this->m_ivars.callback_resolve_infer()); if( ord == ::HIR::Compare::Unequal ) return ord; @@ -1861,6 +1863,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp, t_cb_trait_impl_r callback ) const { + TRACE_FUNCTION_F(trait << FMT_CB(ss, if(params_ptr) { ss << *params_ptr; } else { ss << "<?>"; }) << " for " << type); // TODO: Parameter defaults - apply here or in the caller? return this->m_crate.find_trait_impls(trait, type, this->m_ivars.callback_resolve_infer(), [&](const auto& impl) { @@ -2203,7 +2206,7 @@ const ::HIR::TypeRef* TraitResolution::autoderef(const Span& sp, const ::HIR::Ty } } } -unsigned int TraitResolution::autoderef_find_method(const Span& sp, const HIR::t_trait_list& traits, const ::HIR::TypeRef& top_ty, const ::std::string& method_name, /* Out -> */::HIR::Path& fcn_path) const +unsigned int TraitResolution::autoderef_find_method(const Span& sp, const HIR::t_trait_list& traits, const ::std::vector<unsigned>& ivars, const ::HIR::TypeRef& top_ty, const ::std::string& method_name, /* Out -> */::HIR::Path& fcn_path) const { unsigned int deref_count = 0; ::HIR::TypeRef tmp_type; // Temporary type used for handling Deref @@ -2237,7 +2240,7 @@ unsigned int TraitResolution::autoderef_find_method(const Span& sp, const HIR::t return ~0u; } - if( this->find_method(sp, traits, ty, method_name, unconditional_allow_move || (deref_count == 0), fcn_path) ) { + if( this->find_method(sp, traits, ivars, ty, method_name, unconditional_allow_move || (deref_count == 0), fcn_path) ) { DEBUG("FOUND " << deref_count << ", fcn_path = " << fcn_path); return deref_count; } @@ -2251,7 +2254,7 @@ 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, ty, method_name, true, fcn_path) ) { + if( find_method(sp, traits, ivars, ty, method_name, true, fcn_path) ) { DEBUG("FOUND " << 0 << ", fcn_path = " << fcn_path); return 0; } @@ -2269,7 +2272,7 @@ unsigned int TraitResolution::autoderef_find_method(const Span& sp, const HIR::t } } -bool TraitResolution::find_method(const Span& sp, const HIR::t_trait_list& traits, 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, bool allow_move, /* Out -> */::HIR::Path& fcn_path) const { TRACE_FUNCTION_F("ty=" << ty << ", name=" << method_name); // 1. Search generic bounds for a match @@ -2280,13 +2283,12 @@ bool TraitResolution::find_method(const Span& sp, const HIR::t_trait_list& trait for(const auto& b : p->m_bounds) { TU_IFLET(::HIR::GenericBound, b, TraitBound, e, - DEBUG("Bound " << e.type << " : " << e.trait.m_path); // TODO: Do a fuzzy match here? if( e.type != ty ) continue ; // - Bound's type matches, check if the bounded trait has the method we're searching for - DEBUG("- Matches " << ty); + 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) ) @@ -2421,26 +2423,35 @@ bool TraitResolution::find_method(const Span& sp, const HIR::t_trait_list& trait case ::HIR::Function::Receiver::Value: if( !allow_move ) break; + if(0) + case ::HIR::Function::Receiver::Box: + // NOTE: Only allow picking a `self: Box<Self>` method if we've been through a deref. + if( allow_move ) + break; default: DEBUG("Search for impl of " << *trait_ref.first); - //::HIR::PathParams params; - //for(const auto& t : trait_ref.second->m_params.m_types) { - // (void)t; - // params.m_types.push_back( m_ivars.new_ivar_tr() ); - //} + // Use the set of ivars we were given to populate the trait parameters + unsigned int n_params = trait_ref.second->m_params.m_types.size(); + assert(n_params <= ivars.size()); + ::HIR::PathParams trait_params; + trait_params.m_types.reserve( n_params ); + for(unsigned int i = 0; i < n_params; i++) { + trait_params.m_types.push_back( ::HIR::TypeRef( ::HIR::TypeRef::Data::make_Infer({ ivars[i], ::HIR::InferClass::None }) ) ); + ASSERT_BUG(sp, m_ivars.get_type( trait_params.m_types.back() ).m_data.as_Infer().index == ivars[i], "A method selection ivar was bound"); + } - // TODO: Need a "don't care" marker for the PathParams, because we can't create ivars in this method (or class) - if( find_trait_impls_crate(sp, *trait_ref.first, nullptr, ty, [](auto , auto ) { return true; }) ) { - DEBUG("Found trait impl " << *trait_ref.first << " (" /*<< m_ivars.fmt_type(*trait_ref.first)*/ << ") for " << ty << " ("<<m_ivars.fmt_type(ty)<<")"); + if( find_trait_impls_crate(sp, *trait_ref.first, &trait_params, ty, [](auto , auto ) { return true; }) ) { + DEBUG("Found trait impl " << *trait_ref.first << trait_params << " for " << ty << " ("<<m_ivars.fmt_type(ty)<<")"); fcn_path = ::HIR::Path( ::HIR::Path::Data::make_UfcsKnown({ box$( ty.clone() ), - trait_ref.first->clone(), + ::HIR::GenericPath( *trait_ref.first, mv$(trait_params) ), method_name, {} }) ); return true; } + break; } } } diff --git a/src/hir_typeck/helpers.hpp b/src/hir_typeck/helpers.hpp index dad6cca0..ea85adfc 100644 --- a/src/hir_typeck/helpers.hpp +++ b/src/hir_typeck/helpers.hpp @@ -210,7 +210,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::t_trait_list& traits, const ::HIR::TypeRef& top_ty, const ::std::string& method_name, /* Out -> */::HIR::Path& fcn_path) const; + unsigned int autoderef_find_method(const Span& sp, const HIR::t_trait_list& traits, const ::std::vector<unsigned>& ivars, const ::HIR::TypeRef& top_ty, const ::std::string& method_name, /* Out -> */::HIR::Path& fcn_path) const; /// Locate the named field by applying auto-dereferencing. /// \return Number of times deref was applied (or ~0 if _ was hit) unsigned int autoderef_find_field(const Span& sp, const ::HIR::TypeRef& top_ty, const ::std::string& name, /* Out -> */::HIR::TypeRef& field_type) const; @@ -219,7 +219,7 @@ public: 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 ::HIR::TypeRef& ty, const ::std::string& method_name, bool allow_move, /* Out -> */::HIR::Path& fcn_path) 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; /// 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; |