summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2016-09-24 11:54:53 +0800
committerJohn Hodge <tpg@mutabah.net>2016-09-24 11:54:53 +0800
commit9f05fd7ffc8908ea5c266c40ec11a812fc6309d4 (patch)
tree438eb07c9ce0676d81fc18d86e71e63c38cbcc99 /src
parentb236bbfb13db816666803778b79c22784088efb3 (diff)
downloadmrust-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.hpp5
-rw-r--r--src/hir_typeck/expr_cs.cpp31
-rw-r--r--src/hir_typeck/helpers.cpp41
-rw-r--r--src/hir_typeck/helpers.hpp4
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;