diff options
author | John Hodge <tpg@mutabah.net> | 2016-06-12 21:39:16 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2016-06-12 21:39:16 +0800 |
commit | 1e702d1fb104b6b4a040945d8b18a7afdb216b5e (patch) | |
tree | 381216429f76b11a71b00d463eedab3e06d7fe00 | |
parent | b182c3780e0398921372ecef6780de3d0f89b016 (diff) | |
download | mrust-1e702d1fb104b6b4a040945d8b18a7afdb216b5e.tar.gz |
HIR Typecheck - Rework handling of trait impl searching
-rw-r--r-- | src/hir/path.cpp | 24 | ||||
-rw-r--r-- | src/hir/path.hpp | 2 | ||||
-rw-r--r-- | src/hir/type.cpp | 14 | ||||
-rw-r--r-- | src/hir/type.hpp | 2 | ||||
-rw-r--r-- | src/hir_typeck/expr.cpp | 133 | ||||
-rw-r--r-- | src/hir_typeck/expr.hpp | 20 | ||||
-rw-r--r-- | src/hir_typeck/expr_context.cpp | 465 |
7 files changed, 384 insertions, 276 deletions
diff --git a/src/hir/path.cpp b/src/hir/path.cpp index fb153d7d..6a7e00f7 100644 --- a/src/hir/path.cpp +++ b/src/hir/path.cpp @@ -217,7 +217,7 @@ bool ::HIR::TraitPath::operator==(const ::HIR::TraitPath& x) const } namespace { - ::HIR::Compare compare_with_paceholders( + ::HIR::Compare compare_with_placeholders( const Span& sp, const ::HIR::PathParams& l, const ::HIR::PathParams& r, ::HIR::t_cb_resolve_type resolve_placeholder @@ -232,7 +232,7 @@ namespace { } for( unsigned int i = 0; i < r.m_types.size(); i ++ ) { - auto rv2 = l.m_types[i].compare_with_paceholders( sp, r.m_types[i], resolve_placeholder ); + auto rv2 = l.m_types[i].compare_with_placeholders( sp, r.m_types[i], resolve_placeholder ); if( rv2 == Compare::Unequal ) return Compare::Unequal; if( rv2 == Compare::Fuzzy ) @@ -241,7 +241,7 @@ namespace { } return rv; } - ::HIR::Compare compare_with_paceholders( + ::HIR::Compare compare_with_placeholders( const Span& sp, const ::HIR::GenericPath& l, const ::HIR::GenericPath& r, ::HIR::t_cb_resolve_type resolve_placeholder @@ -259,7 +259,7 @@ namespace { return Compare::Unequal; } - return compare_with_paceholders(sp, l.m_params, r.m_params, resolve_placeholder); + return compare_with_placeholders(sp, l.m_params, r.m_params, resolve_placeholder); } } @@ -271,26 +271,26 @@ namespace { }\ } while(0) -::HIR::Compare HIR::Path::compare_with_paceholders(const Span& sp, const Path& x, t_cb_resolve_type resolve_placeholder) const +::HIR::Compare HIR::Path::compare_with_placeholders(const Span& sp, const Path& x, t_cb_resolve_type resolve_placeholder) const { if( this->m_data.tag() != x.m_data.tag() ) return Compare::Unequal; TU_MATCH(::HIR::Path::Data, (this->m_data, x.m_data), (ple, pre), (Generic, - return ::compare_with_paceholders(sp, ple, pre, resolve_placeholder); + return ::compare_with_placeholders(sp, ple, pre, resolve_placeholder); ), (UfcsUnknown, if( ple.item != pre.item) return Compare::Unequal; - TODO(sp, "Path::compare_with_paceholders - UfcsUnknown"); + TODO(sp, "Path::compare_with_placeholders - UfcsUnknown"); ), (UfcsInherent, if( ple.item != pre.item) return Compare::Unequal; ::HIR::Compare rv = ::HIR::Compare::Equal; - CMP(rv, ple.type->compare_with_paceholders(sp, *pre.type, resolve_placeholder)); - CMP(rv, ::compare_with_paceholders(sp, ple.params, pre.params, resolve_placeholder)); + CMP(rv, ple.type->compare_with_placeholders(sp, *pre.type, resolve_placeholder)); + CMP(rv, ::compare_with_placeholders(sp, ple.params, pre.params, resolve_placeholder)); return rv; ), (UfcsKnown, @@ -298,9 +298,9 @@ namespace { return Compare::Unequal; ::HIR::Compare rv = ::HIR::Compare::Equal; - CMP(rv, ple.type->compare_with_paceholders(sp, *pre.type, resolve_placeholder)); - CMP(rv, ::compare_with_paceholders(sp, ple.trait, pre.trait, resolve_placeholder)); - CMP(rv, ::compare_with_paceholders(sp, ple.params, pre.params, resolve_placeholder)); + CMP(rv, ple.type->compare_with_placeholders(sp, *pre.type, resolve_placeholder)); + CMP(rv, ::compare_with_placeholders(sp, ple.trait, pre.trait, resolve_placeholder)); + CMP(rv, ::compare_with_placeholders(sp, ple.params, pre.params, resolve_placeholder)); return rv; ) ) diff --git a/src/hir/path.hpp b/src/hir/path.hpp index a4603fe3..177a5ada 100644 --- a/src/hir/path.hpp +++ b/src/hir/path.hpp @@ -147,7 +147,7 @@ public: Path(SimplePath _); Path clone() const; - Compare compare_with_paceholders(const Span& sp, const Path& x, t_cb_resolve_type resolve_placeholder) const; + Compare compare_with_placeholders(const Span& sp, const Path& x, t_cb_resolve_type resolve_placeholder) const; friend ::std::ostream& operator<<(::std::ostream& os, const Path& x); }; diff --git a/src/hir/type.cpp b/src/hir/type.cpp index b672c43f..34b0bb2e 100644 --- a/src/hir/type.cpp +++ b/src/hir/type.cpp @@ -495,7 +495,7 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x ) throw ""; } -::HIR::Compare HIR::TypeRef::compare_with_paceholders(const Span& sp, const ::HIR::TypeRef& x, t_cb_resolve_type resolve_placeholder) const +::HIR::Compare HIR::TypeRef::compare_with_placeholders(const Span& sp, const ::HIR::TypeRef& x, t_cb_resolve_type resolve_placeholder) const { TRACE_FUNCTION_F(*this << " ?= " << x); assert( !this->m_data.is_Infer() ); @@ -557,7 +557,7 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x return (le == re ? Compare::Equal : Compare::Unequal); ), (Path, - return le.path.compare_with_paceholders( sp, re.path, resolve_placeholder ); + return le.path.compare_with_placeholders( sp, re.path, resolve_placeholder ); ), (Generic, if( le.binding != re.binding ) @@ -570,10 +570,10 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x (Array, if( le.size_val != re.size_val ) return Compare::Unequal; - return le.inner->compare_with_paceholders(sp, *re.inner, resolve_placeholder); + return le.inner->compare_with_placeholders(sp, *re.inner, resolve_placeholder); ), (Slice, - return le.inner->compare_with_paceholders(sp, *re.inner, resolve_placeholder); + return le.inner->compare_with_placeholders(sp, *re.inner, resolve_placeholder); ), (Tuple, if( le.size() != re.size() ) @@ -581,7 +581,7 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x auto rv = Compare::Equal; for( unsigned int i = 0; i < le.size(); i ++ ) { - auto rv2 = le[i].compare_with_paceholders( sp, re[i], resolve_placeholder ); + auto rv2 = le[i].compare_with_placeholders( sp, re[i], resolve_placeholder ); if( rv2 == Compare::Unequal ) return Compare::Unequal; if( rv2 == Compare::Fuzzy ) @@ -592,12 +592,12 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x (Borrow, if( le.type != re.type ) return Compare::Unequal; - return le.inner->compare_with_paceholders(sp, *re.inner, resolve_placeholder); + return le.inner->compare_with_placeholders(sp, *re.inner, resolve_placeholder); ), (Pointer, if( le.type != re.type ) return Compare::Unequal; - return le.inner->compare_with_paceholders(sp, *re.inner, resolve_placeholder); + return le.inner->compare_with_placeholders(sp, *re.inner, resolve_placeholder); ), (Function, TODO(sp, "Compare " << *this << " and " << right); diff --git a/src/hir/type.hpp b/src/hir/type.hpp index 70a0419d..27757d45 100644 --- a/src/hir/type.hpp +++ b/src/hir/type.hpp @@ -202,7 +202,7 @@ public: bool match_test_generics(const Span& sp, const ::HIR::TypeRef& x, t_cb_resolve_type resolve_placeholder, ::std::function<void(unsigned int, const ::HIR::TypeRef&)> callback) const; // Compares this type with another, using `resolve_placeholder` to get replacements for generics/infers in `x` - Compare compare_with_paceholders(const Span& sp, const ::HIR::TypeRef& x, t_cb_resolve_type resolve_placeholder) const; + Compare compare_with_placeholders(const Span& sp, const ::HIR::TypeRef& x, t_cb_resolve_type resolve_placeholder) const; }; extern ::std::ostream& operator<<(::std::ostream& os, const ::HIR::TypeRef& ty); diff --git a/src/hir_typeck/expr.cpp b/src/hir_typeck/expr.cpp index e800a784..d14424b2 100644 --- a/src/hir_typeck/expr.cpp +++ b/src/hir_typeck/expr.cpp @@ -648,16 +648,17 @@ namespace typeck { } assert(lang_item); const auto& trait_path = this->context.m_crate.get_lang_item_path(node.span(), lang_item); + ::HIR::PathParams trait_path_pp; + trait_path_pp.m_types.push_back( ty_right.clone() ); - - /*bool rv =*/ this->context.find_trait_impls(trait_path, ty_left, [&](const auto& args) { + /*bool rv =*/ this->context.find_trait_impls(node.span(), trait_path,trait_path_pp, ty_left, [&](const auto& args, const auto& a_types) { assert( args.m_types.size() == 1 ); const auto& impl_right = args.m_types[0]; TODO(node.span(), "Check " << impl_right << " vs " << ty_right); - //auto cmp = impl_index.compare_with_paceholders(node.span(), index_ty, this->context.callback_resolve_infer()); + //auto cmp = impl_index.compare_with_placeholders(node.span(), index_ty, this->context.callback_resolve_infer()); //if( cmp == ::HIR::Compare::Unequal) // return false; //if( cmp == ::HIR::Compare::Equal ) { @@ -681,7 +682,7 @@ namespace typeck { const auto& ty_right = this->context.get_type(node.m_right->m_res_type); const auto& ty_res = this->context.get_type(node.m_res_type); - DEBUG("BinOp " << ty_left << " <> " << ty_right << " = " << ty_res); + TRACE_FUNCTION_FR("BinOp " << ty_left << " <> " << ty_right << " = " << ty_res, "BinOp"); // Boolean ops can't be overloaded, and require `bool` on both sides if( node.m_op == ::HIR::ExprNode_BinOp::Op::BoolAnd || node.m_op == ::HIR::ExprNode_BinOp::Op::BoolOr ) @@ -856,6 +857,10 @@ namespace typeck { } else { + const auto& ty_left = this->context.get_type(node.m_left->m_res_type ); + const auto& ty_right = this->context.get_type(node.m_right->m_res_type); + //const auto& ty_res = this->context.get_type(node.m_res_type); + const char* item_name = nullptr; bool has_output = true; switch(node.m_op) @@ -889,13 +894,15 @@ namespace typeck { ::HIR::TypeRef possible_right_type; unsigned int count = 0; const auto& ops_trait = this->context.m_crate.get_lang_item_path(node.span(), item_name); + ::HIR::PathParams ops_trait_pp; + ops_trait_pp.m_types.push_back( ty_right.clone() ); DEBUG("Searching for impl " << ops_trait << "< " << ty_right << "> for " << ty_left); - bool found_bound = this->context.find_trait_impls_bound(sp, ops_trait, ty_left, + bool found_bound = this->context.find_trait_impls_bound(sp, ops_trait, ops_trait_pp, ty_left, [&](const auto& args, const auto& assoc) { assert(args.m_types.size() == 1); const auto& arg_type = args.m_types[0]; // TODO: if arg_type mentions Self? - auto cmp = arg_type.compare_with_paceholders(node.span(), ty_right, this->context.callback_resolve_infer()); + auto cmp = arg_type.compare_with_placeholders(node.span(), ty_right, this->context.callback_resolve_infer()); if( cmp == ::HIR::Compare::Unequal ) { DEBUG("- (fail) bounded impl " << ops_trait << "<" << arg_type << "> (ty_right = " << this->context.get_type(ty_right)); return false; @@ -919,38 +926,11 @@ namespace typeck { assert( impl.m_trait_args.m_types.size() == 1 ); const auto& arg_type = impl.m_trait_args.m_types[0]; - // TODO: Abstract the below code into a method on TypecheckContext - // 1. Match arg_type with ty_right into impl block params - bool fail = false; - ::std::vector< const ::HIR::TypeRef*> impl_params; - impl_params.resize( impl.m_params.m_types.size() ); - auto cb = [&](auto idx, const auto& ty) { - assert( idx < impl_params.size() ); - DEBUG(idx << " = " << ty); - if( impl_params[idx] ) { - if( *impl_params[idx] != ty ) { - fail = true; - } - } - else { - impl_params[idx] = &ty; - } - }; - fail |= !impl.m_type.match_test_generics(node.span(), ty_left , this->context.callback_resolve_infer(), cb); - fail |= !arg_type .match_test_generics(node.span(), ty_right, this->context.callback_resolve_infer(), cb); - for(const auto& ty : impl_params) - assert( ty ); - if( fail ) { - DEBUG("- (generic fail) impl" << impl.m_params.fmt_args() << " " << ops_trait << "<" << arg_type << "> for " << impl.m_type); - return false; - } - - // TODO: handle a generic righthand type by using the above parameters if( monomorphise_type_needed(arg_type) ) { return true; //TODO(node.span(), "Compare ops trait type when it contains generics - " << arg_type << " == " << ty_right); } - auto cmp = arg_type.compare_with_paceholders(node.span(), ty_right, this->context.callback_resolve_infer()); + auto cmp = arg_type.compare_with_placeholders(node.span(), ty_right, this->context.callback_resolve_infer()); if( cmp == ::HIR::Compare::Unequal ) { return false; } @@ -1153,24 +1133,26 @@ namespace typeck { ::HIR::TypeRef tmp_type; // Temporary type used for handling Deref const auto* current_ty = &node.m_value->m_res_type; - const auto& index_ty = this->context.get_type(node.m_index->m_res_type); + ::HIR::PathParams trait_pp; + trait_pp.m_types.push_back( this->context.get_type(node.m_index->m_res_type).clone() ); do { const auto& ty = this->context.get_type(*current_ty); - DEBUG("_Index: (: " << ty << ")[: " << index_ty << "]"); + DEBUG("_Index: (: " << ty << ")[: " << trait_pp.m_types[0] << "]"); - ::HIR::TypeRef possible_type; + ::HIR::TypeRef possible_index_type; unsigned int count = 0; - bool rv = this->context.find_trait_impls(path_Index, ty, [&](const auto& args) { + bool rv = this->context.find_trait_impls(node.span(), path_Index,trait_pp, ty, [&](const auto& args, const auto& assoc) { assert( args.m_types.size() == 1 ); const auto& impl_index = args.m_types[0]; - auto cmp = impl_index.compare_with_paceholders(node.span(), index_ty, this->context.callback_resolve_infer()); + auto cmp = impl_index.compare_with_placeholders(node.span(), trait_pp.m_types[0], this->context.callback_resolve_infer()); if( cmp == ::HIR::Compare::Unequal) return false; + // TODO: use `assoc` if( cmp == ::HIR::Compare::Equal ) { return true; } - possible_type = impl_index.clone(); + possible_index_type = impl_index.clone(); count += 1; return false; }); @@ -1178,7 +1160,8 @@ namespace typeck { break; } else if( count == 1 ) { - this->context.apply_equality(node.span(), index_ty, possible_type); + assert( possible_index_type != ::HIR::TypeRef() ); + this->context.apply_equality(node.span(), node.m_index->m_res_type, possible_index_type); break; } else { @@ -1526,46 +1509,53 @@ namespace typeck { (TraitBound, auto real_type = monomorphise_type_with(sp, be.type, cache.m_monomorph_cb); auto real_trait = monomorphise_genericpath_with(sp, be.trait.m_path, cache.m_monomorph_cb, false); - DEBUG("Bound " << be.type << " (" << real_type << ") : " << be.trait << " (" << real_trait << ")"); + DEBUG("Bound " << be.type << ": " << be.trait); + DEBUG("= (" << real_type << ": " << real_trait << ")"); auto monomorph_bound = [&](const auto& gt)->const auto& { return gt; - // TODO: Should this expand to the impl type? - // - Probably not, as that's `find_trait_impls`'s job - /* - const auto& ge = gt.m_data.as_Generic(); - if( ge.binding == 0xFFFF ) - return real_type; - else { - TODO(sp, "visit_call::monomorph_bound - Handle generic " << gt); - } - */ }; const auto& trait_params = be.trait.m_path.m_params; // TODO: Detect marker traits - auto rv = this->context.find_trait_impls(be.trait.m_path.m_path, real_type, [&](const auto& pp) { + const auto& trait_gp = be.trait.m_path; + auto rv = this->context.find_trait_impls(sp, trait_gp.m_path, real_trait.m_params, real_type, [&](const auto& pp, const auto& at) { if( pp.m_types.size() != trait_params.m_types.size() ) { BUG(sp, "Parameter mismatch"); } - if( pp.m_types.size() > 0 ) - { - DEBUG("Check equality of " << pp << " and " << trait_params << " (once monomorphed)"); - // HACK! Just assume it's good and match. - // - This could have a false negative (if there's multiple impls of the trait with different params) - // - OR, it could false positive (Possible? Specialisation) - for(unsigned int i = 0; i < pp.m_types.size(); i ++ ) { - auto l = monomorphise_type_with(sp, pp.m_types[i], monomorph_bound); - auto r = monomorphise_type_with(sp, trait_params.m_types[i], cache.m_monomorph_cb); - DEBUG(i << " " << l << " and " << r); - this->context.apply_equality(sp, pp.m_types[i], monomorph_bound, trait_params.m_types[i], cache.m_monomorph_cb, nullptr); - } + DEBUG("Apply equality of " << pp << " and " << trait_params << " (once monomorphed)"); + for(unsigned int i = 0; i < pp.m_types.size(); i ++ ) { + auto& l = pp.m_types[i]; + auto r = monomorphise_type_with(sp, trait_params.m_types[i], cache.m_monomorph_cb); + DEBUG(i << " " << l << " and " << r); + //this->context.apply_equality(sp, pp.m_types[i], monomorph_bound, trait_params.m_types[i], cache.m_monomorph_cb, nullptr); + this->context.apply_equality(sp, pp.m_types[i], monomorph_bound, real_trait.m_params.m_types[i], IDENT_CR, nullptr); + } + // TODO: Use `at` + // - Check if the associated type bounds are present + #if 0 + for( const auto& assoc : be.trait.m_type_bounds ) { + auto it = at.find( assoc.first ); + if( it == at.end() ) + TODO(sp, "Bounded associated type " << assoc.first << " wasn't in list provided by find_trait_impls"); + DEBUG("Equate (impl) " << it->second << " and (bound) " << assoc.second); + //this->context.apply_equality(sp, it->second, IDENT_CR, assoc.second, cache.m_monomorph_cb, nullptr); + auto other_ty = monomorphise_type_with(sp, assoc.second, cache.m_monomorph_cb, true); + this->context.apply_equality(sp, it->second, other_ty); } + DEBUG("at = " << at); + #endif return true; }); if( !rv ) { - // Continue or error? (Need a fuzzy return from the above) + // TODO: Enable this once marker impls are checked correctly + //if( this->context.type_contains_ivars(real_type) ) { + // ERROR(sp, E0000, "No suitable impl of " << real_trait << " for " << real_type); + //} DEBUG("- No impl of " << be.trait.m_path << " for " << real_type); continue ; } + // TODO: Only do this if associated type was missing in list from impl + // - E.g. FnMut<Output=Bar> + #if 1 for( const auto& assoc : be.trait.m_type_bounds ) { auto ty = ::HIR::TypeRef( ::HIR::Path(::HIR::Path::Data::Data_UfcsKnown { box$(real_type.clone()), be.trait.m_path.clone(), assoc.first, {} }) ); // TODO: I'd like to avoid this copy, but expand_associated_types doesn't use the monomorph callback @@ -1574,7 +1564,7 @@ namespace typeck { //this->context.apply_equality( sp, ty, [](const auto&x)->const auto&{return x;}, assoc.csecond, cache.m_monomorph_cb, nullptr ); this->context.apply_equality( sp, ty, other_ty ); } - + #endif ), (TypeEquality, #if 0 @@ -1618,7 +1608,9 @@ namespace typeck { ::HIR::TypeRef fcn_ret; // Locate impl of FnOnce const auto& lang_FnOnce = this->context.m_crate.get_lang_item_path(node.span(), "fn_once"); - auto was_bounded = this->context.find_trait_impls_bound(node.span(), lang_FnOnce, ty, [&](const auto& args, const auto& assoc) { + ::HIR::PathParams trait_pp; + trait_pp.m_types.push_back( this->context.new_ivar_tr() ); // TODO: Bind to arguments? + auto was_bounded = this->context.find_trait_impls_bound(node.span(), lang_FnOnce, trait_pp, ty, [&](const auto& args, const auto& assoc) { const auto& tup = args.m_types[0]; if( !tup.m_data.is_Tuple() ) ERROR(node.span(), E0000, "FnOnce expects a tuple argument, got " << tup); @@ -1649,6 +1641,11 @@ namespace typeck { node.m_arg_types = mv$( fcn_args_tup.m_data.as_Tuple() ); node.m_arg_types.push_back( mv$(fcn_ret) ); ), + (Closure, + for( const auto& arg : e.m_arg_types ) + node.m_arg_types.push_back( arg.clone() ); + node.m_arg_types.push_back( e.m_rettype->clone() ); + ), (Function, for( const auto& arg : e.m_arg_types ) node.m_arg_types.push_back( arg.clone() ); diff --git a/src/hir_typeck/expr.hpp b/src/hir_typeck/expr.hpp index 749c7d1a..0eb3b1d4 100644 --- a/src/hir_typeck/expr.hpp +++ b/src/hir_typeck/expr.hpp @@ -5,6 +5,8 @@ #include <hir/hir.hpp> #include <hir/visitor.hpp> +#define IDENT_CR ([](const auto& v)->const auto&{return v;}) + namespace typeck { // TODO/NOTE - This is identical to ::HIR::t_cb_resolve_type @@ -85,6 +87,9 @@ public: /// Apply defaults (i32 or f64), returns true if a default was applied bool apply_defaults(); + bool pathparams_contain_ivars(const ::HIR::PathParams& pps) const; + bool type_contains_ivars(const ::HIR::TypeRef& ty) const; + /// Adds a local variable binding (type is mutable so it can be inferred if required) void add_local(unsigned int index, const ::std::string& name, ::HIR::TypeRef type); @@ -129,25 +134,26 @@ public: /// Iterate over in-scope bounds (function then top) bool iterate_bounds( ::std::function<bool(const ::HIR::GenericBound&)> cb) const; - /// Searches for a trait impl that matches the provided trait name and type - bool find_trait_impls(const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, ::std::function<bool(const ::HIR::PathParams&)> callback) const; - typedef ::std::function<bool(const ::HIR::PathParams&, const ::std::map< ::std::string,::HIR::TypeRef>&)> t_cb_trait_impl; + + /// Searches for a trait impl that matches the provided trait name and type + bool find_trait_impls(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& type, t_cb_trait_impl callback) const; /// Locate a named trait in the provied trait (either itself or as a parent trait) bool find_named_trait_in_trait(const Span& sp, - const ::HIR::SimplePath& des, + const ::HIR::SimplePath& des, const ::HIR::PathParams& params, const ::HIR::Trait& trait_ptr, const ::HIR::SimplePath& trait_path, const ::HIR::PathParams& pp, const ::HIR::TypeRef& self_type, t_cb_trait_impl callback ) const; /// Search for a trait implementation in current bounds - bool find_trait_impls_bound(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, t_cb_trait_impl callback) const; + bool find_trait_impls_bound(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& type, t_cb_trait_impl callback) const; /// Search for a trait implementation in the crate - bool find_trait_impls_crate(const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, ::std::function<bool(const ::HIR::PathParams&)> callback) const; + bool find_trait_impls_crate(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& type, t_cb_trait_impl callback) 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, ::HIR::GenericPath& out_path) const; + bool trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::std::string& name, ::HIR::GenericPath& out_path) const; const ::HIR::TypeRef* autoderef(const Span& sp, const ::HIR::TypeRef& ty, ::HIR::TypeRef& tmp_type) const; /// Locate the named method by applying auto-dereferencing. @@ -159,7 +165,7 @@ public: bool find_field(const Span& sp, const ::HIR::TypeRef& ty, const ::std::string& name, /* Out -> */::HIR::TypeRef& field_type) const; public: - ::std::function<const ::HIR::TypeRef&(const ::HIR::TypeRef&)> callback_resolve_infer() { + ::std::function<const ::HIR::TypeRef&(const ::HIR::TypeRef&)> callback_resolve_infer() const { return [&](const auto& ty)->const auto& { if( ty.m_data.is_Infer() ) return this->get_type(ty); diff --git a/src/hir_typeck/expr_context.cpp b/src/hir_typeck/expr_context.cpp index 56fbe654..4d7980ad 100644 --- a/src/hir_typeck/expr_context.cpp +++ b/src/hir_typeck/expr_context.cpp @@ -99,6 +99,84 @@ const ::HIR::TypeRef& typeck::TypecheckContext::get_var_type(const Span& sp, uns return m_locals.at(index).type; } + +bool typeck::TypecheckContext::pathparams_contain_ivars(const ::HIR::PathParams& pps) const { + for( const auto& ty : pps.m_types ) { + if(this->type_contains_ivars(ty)) + return true; + } + return false; +} +bool typeck::TypecheckContext::type_contains_ivars(const ::HIR::TypeRef& ty) const { + TU_MATCH(::HIR::TypeRef::Data, (this->get_type(ty).m_data), (e), + (Infer, return true; ), + (Primitive, return false; ), + (Diverge, return false; ), + (Generic, return false; ), + (Path, + TU_MATCH(::HIR::Path::Data, (e.path.m_data), (pe), + (Generic, + return pathparams_contain_ivars(pe.m_params); + ), + (UfcsKnown, + if( type_contains_ivars(*pe.type) ) + return true; + if( pathparams_contain_ivars(pe.trait.m_params) ) + return true; + return pathparams_contain_ivars(pe.params); + ), + (UfcsInherent, + if( type_contains_ivars(*pe.type) ) + return true; + return pathparams_contain_ivars(pe.params); + ), + (UfcsUnknown, + BUG(Span(), "UfcsUnknown"); + ) + ) + ), + (Borrow, + return type_contains_ivars(*e.inner); + ), + (Pointer, + return type_contains_ivars(*e.inner); + ), + (Slice, + return type_contains_ivars(*e.inner); + ), + (Array, + return type_contains_ivars(*e.inner); + ), + (Closure, + for(const auto& arg : e.m_arg_types) + if( type_contains_ivars(arg) ) + return true; + return type_contains_ivars(*e.m_rettype); + ), + (Function, + for(const auto& arg : e.m_arg_types) + if( type_contains_ivars(arg) ) + return true; + return type_contains_ivars(*e.m_rettype); + ), + (TraitObject, + for(const auto& marker : e.m_markers) + if( pathparams_contain_ivars(marker.m_params) ) + return true; + return pathparams_contain_ivars(e.m_trait.m_path.m_params); + ), + (Tuple, + for(const auto& st : e) + if( type_contains_ivars(st) ) + return true; + return false; + ) + ) + throw ""; +} + + + /// /// Add inferrence variables to the provided type (if they're not already set) /// @@ -814,80 +892,12 @@ void typeck::TypecheckContext::apply_equality(const Span& sp, const ::HIR::TypeR // If either side is UFCS, and still contains unconstrained ivars - don't error struct H { - static bool pathparams_contain_ivars(const TypecheckContext& context, const ::HIR::PathParams& pps) { - for( const auto& ty : pps.m_types ) { - if(H::type_contains_ivars(context, ty)) - return true; - } - return false; - } - static bool type_contains_ivars(const TypecheckContext& context, const ::HIR::TypeRef& ty) { - TU_MATCH(::HIR::TypeRef::Data, (context.get_type(ty).m_data), (e), - (Infer, return true; ), - (Primitive, return false; ), - (Diverge, return false; ), - (Generic, return false; ), - (Path, - TU_MATCH(::HIR::Path::Data, (e.path.m_data), (pe), - (Generic, - return H::pathparams_contain_ivars(context, pe.m_params); - ), - (UfcsKnown, - if( H::type_contains_ivars(context, *pe.type) ) - return true; - if( H::pathparams_contain_ivars(context, pe.trait.m_params) ) - return true; - return H::pathparams_contain_ivars(context, pe.params); - ), - (UfcsInherent, - if( H::type_contains_ivars(context, *pe.type) ) - return true; - return H::pathparams_contain_ivars(context, pe.params); - ), - (UfcsUnknown, - BUG(Span(), "UfcsUnknown"); - ) - ) - ), - (Borrow, - return type_contains_ivars(context, *e.inner); - ), - (Pointer, - return type_contains_ivars(context, *e.inner); - ), - (Slice, - return type_contains_ivars(context, *e.inner); - ), - (Array, - return type_contains_ivars(context, *e.inner); - ), - (Closure, - TODO(Span(), "Closure"); - ), - (Function, - TODO(Span(), "Closure"); - ), - (TraitObject, - for(const auto& marker : e.m_markers) - if( H::pathparams_contain_ivars(context, marker.m_params) ) - return true; - return H::pathparams_contain_ivars(context, e.m_trait.m_path.m_params); - ), - (Tuple, - for(const auto& st : e) - if( type_contains_ivars(context, st) ) - return true; - return false; - ) - ) - throw ""; - } static bool type_is_free_ufcs(const TypecheckContext& context, const ::HIR::TypeRef& ty) { TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Path, e, if( e.path.m_data.is_Generic() ) { return false; } - return type_contains_ivars(context, ty); + return context.type_contains_ivars(ty); ) return false; } @@ -1011,7 +1021,9 @@ void typeck::TypecheckContext::apply_equality(const Span& sp, const ::HIR::TypeR const auto& right_inner_res = this->get_type(*r_e.inner); // Allow cases where `right`: ::core::marker::Unsize<`left`> - bool succ = this->find_trait_impls(this->m_crate.get_lang_item_path(sp, "unsize"), right_inner_res, [&](const auto& args) { + ::HIR::PathParams pp; + pp.m_types.push_back( left_inner_res.clone() ); + bool succ = this->find_trait_impls(sp, this->m_crate.get_lang_item_path(sp, "unsize"), pp, right_inner_res, [&](const auto& args, const auto& ) { DEBUG("- Found unsizing with args " << args); return args.m_types[0] == left_inner_res; }); @@ -1041,9 +1053,10 @@ void typeck::TypecheckContext::apply_equality(const Span& sp, const ::HIR::TypeR } // 1. Search for an implementation of the data trait for this type - bool succ = this->find_trait_impls(e.m_trait.m_path.m_path, right_inner_res, [&](const auto& args) { + bool succ = this->find_trait_impls(sp, e.m_trait.m_path.m_path, e.m_trait.m_path.m_params, right_inner_res, [&](const auto& args,const auto& types) { if( args.m_types.size() > 0 ) TODO(sp, "Handle unsizing to traits with params"); + // TODO: Check `types` return true; }); if(!succ) @@ -1143,7 +1156,7 @@ void typeck::TypecheckContext::apply_equality(const Span& sp, const ::HIR::TypeR // ------------------------------------------------------------------------------------------------------------------- bool typeck::TypecheckContext::check_trait_bound(const Span& sp, const ::HIR::TypeRef& type, const ::HIR::GenericPath& trait, ::std::function<const ::HIR::TypeRef&(const ::HIR::TypeRef&)> placeholder) const { - if( this->find_trait_impls_bound(sp, trait.m_path, placeholder(type), [&](const auto& args, const auto& _){ + if( this->find_trait_impls_bound(sp, trait.m_path, trait.m_params, placeholder(type), [&](const auto& args, const auto& _){ DEBUG("TODO: Check args for " << trait.m_path << args << " against " << trait); return true; }) @@ -1183,9 +1196,12 @@ bool typeck::TypecheckContext::iterate_bounds( ::std::function<bool(const ::HIR: } return false; } -bool typeck::TypecheckContext::find_trait_impls(const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, ::std::function<bool(const ::HIR::PathParams&)> callback) const +bool typeck::TypecheckContext::find_trait_impls(const Span& sp, + const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, + const ::HIR::TypeRef& type, + t_cb_trait_impl callback + ) const { - Span sp = Span(); TRACE_FUNCTION_F("trait = " << trait << ", type = " << type); // Closures are magical. They're unnamable and all trait impls come from within the compiler @@ -1193,16 +1209,28 @@ bool typeck::TypecheckContext::find_trait_impls(const ::HIR::SimplePath& trait, const auto trait_fn = this->m_crate.get_lang_item_path(sp, "fn"); const auto trait_fn_mut = this->m_crate.get_lang_item_path(sp, "fn_mut"); const auto trait_fn_once = this->m_crate.get_lang_item_path(sp, "fn_once"); + if( trait == trait_fn || trait == trait_fn_mut || trait == trait_fn_once ) { - // NOTE: This is a conditional "true", we know nothing about the move/mut-ness of this closure yet - // - Could we? + if( params.m_types.size() != 1 ) + BUG(sp, "Fn* traits require a single tuple argument"); + TU_MATCH_DEF( ::HIR::TypeRef::Data, (params.m_types[0].m_data), (te), + ( + ), + (Tuple, + ) + ) ::std::vector< ::HIR::TypeRef> args; for(const auto& at : e.m_arg_types) { args.push_back( at.clone() ); } + + // NOTE: This is a conditional "true", we know nothing about the move/mut-ness of this closure yet + // - Could we? ::HIR::PathParams pp; pp.m_types.push_back( ::HIR::TypeRef(mv$(args)) ); - return callback( pp ); + ::std::map< ::std::string, ::HIR::TypeRef> types; + types.insert( ::std::make_pair( "Output", e.m_rettype->clone() ) ); + return callback( pp, types ); } else { return false; @@ -1210,10 +1238,10 @@ bool typeck::TypecheckContext::find_trait_impls(const ::HIR::SimplePath& trait, ) // 1. Search generic params - if( find_trait_impls_bound(sp, trait, type, [&callback](const auto& pp, const auto& _) { return callback(pp); }) ) + if( find_trait_impls_bound(sp, trait, params, type, callback) ) return true; // 2. Search crate-level impls - return find_trait_impls_crate(trait, type, callback); + return find_trait_impls_crate(sp, trait, params, type, callback); } // ------------------------------------------------------------------------------------------------------------------- @@ -1226,11 +1254,12 @@ bool typeck::TypecheckContext::find_trait_impls(const ::HIR::SimplePath& trait, (Infer, auto& ty = this->get_type(input); if( ty != input ) { - return expand_associated_types(sp, ty.clone()); + input = expand_associated_types(sp, ty.clone()); + return input; } else { - return input; } + return input; ), (Diverge, ), @@ -1273,17 +1302,6 @@ bool typeck::TypecheckContext::find_trait_impls(const ::HIR::SimplePath& trait, } ) - // Search for a matching trait impl - const ::HIR::TraitImpl* impl_ptr = nullptr; - ::std::vector< const ::HIR::TypeRef*> impl_args; - - auto cb_get_infer = [&](const auto& ty)->const auto& { - if( ty.m_data.is_Infer() ) - return this->get_type(ty); - else - return ty; - }; - // 1. Bounds bool rv; bool assume_opaque = true; @@ -1314,7 +1332,7 @@ bool typeck::TypecheckContext::find_trait_impls(const ::HIR::SimplePath& trait, } bool found_supertrait = this->find_named_trait_in_trait(sp, - e2.trait.m_path, + e2.trait.m_path, e2.trait.m_params, *be.trait.m_trait_ptr, be.trait.m_path.m_path, be.trait.m_path.m_params, *e2.type, [&e2,&input,&assume_opaque](const auto& x, const auto& assoc){ auto it = assoc.find(e2.item); @@ -1359,6 +1377,7 @@ bool typeck::TypecheckContext::find_trait_impls(const ::HIR::SimplePath& trait, DEBUG("Assuming that " << input << " is an opaque name"); input.m_data.as_Path().binding = ::HIR::TypeRef::TypePathBinding::make_Opaque({}); } + input = this->expand_associated_types(sp, mv$(input)); return input; } @@ -1421,7 +1440,7 @@ bool typeck::TypecheckContext::find_trait_impls(const ::HIR::SimplePath& trait, (TypeEquality, // IF: bound's type matches the input, replace with bounded equality // `<Self::IntoIter as Iterator>::Item = Self::Item` - if( be.type.compare_with_paceholders(sp, input, cb_placeholders_type ) ) { + if( be.type.compare_with_placeholders(sp, input, cb_placeholders_type ) ) { DEBUG("Match of " << be.type << " with " << input); DEBUG("- Replace `input` with " << be.other_type << ", Self=" << *pe_inner.type); if( monomorphise_type_needed(be.other_type) ) { @@ -1439,88 +1458,31 @@ bool typeck::TypecheckContext::find_trait_impls(const ::HIR::SimplePath& trait, ) // 2. Crate-level impls - rv = this->m_crate.find_trait_impls(e2.trait.m_path, *e2.type, cb_get_infer, - [&](const auto& impl) { - DEBUG("Found impl" << impl.m_params.fmt_args() << " " << e2.trait.m_path << impl.m_trait_args << " for " << impl.m_type); - // - Populate the impl's type arguments - impl_args.clear(); - impl_args.resize( impl.m_params.m_types.size() ); - // - Match with `Self` - auto cb_res = [&](unsigned int slot, const ::HIR::TypeRef& ty) { - DEBUG("- Set " << slot << " = " << ty); - if( slot >= impl_args.size() ) { - BUG(sp, "Impl parameter out of range - " << slot); - } - auto& slot_r = impl_args.at(slot); - if( slot_r != nullptr ) { - DEBUG("TODO: Match " << slot_r << " == " << ty << " when encountered twice"); - } - else { - slot_r = &ty; - } - }; - bool fail = false; - fail |= !impl.m_type.match_test_generics(sp, *e2.type, cb_get_infer, cb_res); - for( unsigned int i = 0; i < impl.m_trait_args.m_types.size(); i ++ ) - { - fail |= !impl.m_trait_args.m_types[i].match_test_generics(sp, e2.trait.m_params.m_types.at(i), cb_get_infer, cb_res); - } - if( fail ) { - return false; - } - auto expand_placeholder = [&](const auto& ty)->const auto& { - if( ty.m_data.is_Infer() ) - return this->get_type(ty); - else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Generic, e, - if( e.binding == 0xFFFF ) { - //TODO(sp, "Look up 'Self' in expand_associated_types::expand_placeholder (" << *e2.type << ")"); - return *e2.type; - } - else if( e.binding < 256 ) { - assert(e.binding < impl_args.size()); - assert( impl_args[e.binding] ); - return *impl_args[e.binding]; - } - else { - BUG(sp, "Encountered fn-level params? " << ty); - } - ) - else - return ty; - }; - for( const auto& bound : impl.m_params.m_bounds ) - { - TU_MATCH_DEF(::HIR::GenericBound, (bound), (be), - ( - ), - (TraitBound, - DEBUG("- Checking bound - " << be.type << " : " << be.trait.m_path); - if( !this->check_trait_bound(sp, be.type, be.trait.m_path, expand_placeholder) ) - { - return false; - } - ) - ) - } - impl_ptr = &impl; - return true; - }); - if( rv ) - { - // An impl was found: - assert(impl_ptr); + // TODO: Search for the actual trait containing this associated type + ::HIR::GenericPath trait_path; + if( !this->trait_contains_type(sp, e2.trait, this->m_crate.get_trait_by_path(sp, e2.trait.m_path), e2.item, trait_path) ) + BUG(sp, "Cannot find associated type " << e2.item << " anywhere in trait " << e2.trait); + //e2.trait = mv$(trait_path); + + rv = this->find_trait_impls_crate(sp, trait_path.m_path, trait_path.m_params, *e2.type, [&](const auto& args, const auto& assoc) { + DEBUG("Found impl for " << e2.trait.m_path << args << " with types {" << assoc << "}"); + auto it = assoc.find( e2.item ); + if( it == assoc.end() ) + ERROR(sp, E0000, "Couldn't find assocated type " << e2.item << " in " << e2.trait); - // - Monomorphise the output type - auto new_type = monomorphise_type_with(sp, impl_ptr->m_types.at( e2.item ), [&](const auto& ty)->const auto& { - const auto& ge = ty.m_data.as_Generic(); - assert(ge.binding < impl_args.size()); - return *impl_args[ge.binding]; - }); - DEBUG("Converted UfcsKnown - " << e.path << " = " << new_type << " using " << e2.item << " = " << impl_ptr->m_types.at( e2.item )); - return expand_associated_types(sp, mv$(new_type)); + DEBUG("Converted UfcsKnown - " << e.path << " = " << it->second); + input = it->second.clone(); + return true; + }); + if( rv ) { + input = this->expand_associated_types(sp, mv$(input)); + return input; } // TODO: If there are no ivars in this path, set its binding to Opaque + if( !this->type_contains_ivars(input) ) { + e.binding = ::HIR::TypeRef::TypePathBinding::make_Opaque({}); + } DEBUG("Couldn't resolve associated type for " << input); ), @@ -1566,7 +1528,7 @@ bool typeck::TypecheckContext::find_trait_impls(const ::HIR::SimplePath& trait, // // ------------------------------------------------------------------------------------------------------------------- bool typeck::TypecheckContext::find_named_trait_in_trait(const Span& sp, - const ::HIR::SimplePath& des, + const ::HIR::SimplePath& des, const ::HIR::PathParams& des_params, const ::HIR::Trait& trait_ptr, const ::HIR::SimplePath& trait_path, const ::HIR::PathParams& pp, const ::HIR::TypeRef& target_type, t_cb_trait_impl callback @@ -1598,25 +1560,50 @@ bool typeck::TypecheckContext::find_named_trait_in_trait(const Span& sp, } return false; } -bool typeck::TypecheckContext::find_trait_impls_bound(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, t_cb_trait_impl callback) const +bool typeck::TypecheckContext::find_trait_impls_bound(const Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& type, t_cb_trait_impl callback) const { return this->iterate_bounds([&](const auto& b) { TU_IFLET(::HIR::GenericBound, b, TraitBound, e, + // TODO: Allow fuzzy equality? if( e.type != type ) return false; + if( e.trait.m_path.m_path == trait ) { + const auto& b_params = e.trait.m_path.m_params; + if( params.m_types.size() != b_params.m_types.size() ) { + // Bug? + BUG(sp, "Paremter count mismatch"); + } + DEBUG("Checking " << params << " vs " << b_params); + bool is_fuzzy = false; + // Check against `params` + for(unsigned int i = 0; i < params.m_types.size(); i ++) { + auto ord = b_params.m_types[i].compare_with_placeholders(sp, params.m_types[i], this->callback_resolve_infer()); + if( ord == ::HIR::Compare::Unequal ) + return false; + if( ord == ::HIR::Compare::Fuzzy ) + is_fuzzy = true; + } + if( is_fuzzy ) { + DEBUG("Fuzzy match"); + } + // Hand off to the closure, and return true if it does if( callback(e.trait.m_path.m_params, e.trait.m_type_bounds) ) { return true; } } - if( this->find_named_trait_in_trait(sp, trait, *e.trait.m_trait_ptr, e.trait.m_path.m_path, e.trait.m_path.m_params, type, callback) ) { + if( this->find_named_trait_in_trait(sp, trait,params, *e.trait.m_trait_ptr, e.trait.m_path.m_path, e.trait.m_path.m_params, type, callback) ) { return true; } ) return false; }); } -bool typeck::TypecheckContext::find_trait_impls_crate(const ::HIR::SimplePath& trait, const ::HIR::TypeRef& type, ::std::function<bool(const ::HIR::PathParams&)> callback) const +bool typeck::TypecheckContext::find_trait_impls_crate(const Span& sp, + const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, + const ::HIR::TypeRef& type, + t_cb_trait_impl callback + ) const { return this->m_crate.find_trait_impls(trait, type, [&](const auto& ty)->const auto&{ if( ty.m_data.is_Infer() ) @@ -1626,7 +1613,98 @@ bool typeck::TypecheckContext::find_trait_impls_crate(const ::HIR::SimplePath& t }, [&](const auto& impl) { DEBUG("[find_trait_impls_crate] Found impl" << impl.m_params.fmt_args() << " " << trait << impl.m_trait_args << " for " << impl.m_type); - return callback(impl.m_trait_args); + // Compare with `params` + // - TODO: Would prefer a fuzzy compare, but match is easiest + bool fail = false; + ::std::vector< const ::HIR::TypeRef*> impl_params; + impl_params.resize( impl.m_params.m_types.size() ); + auto cb = [&](auto idx, const auto& ty) { + DEBUG("[find_trait_impls_crate] " << idx << " = " << ty); + assert( idx < impl_params.size() ); + if( ! impl_params[idx] ) { + impl_params[idx] = &ty; + } + else if( *impl_params[idx] != ty ) { + fail = true; + } + else { + } + }; + assert( impl.m_trait_args.m_types.size() == params.m_types.size() ); + fail |= !impl.m_type.match_test_generics(sp, type , this->callback_resolve_infer(), cb); + for(unsigned int i = 0; i < impl.m_trait_args.m_types.size(); i ++) + fail |= !impl.m_trait_args.m_types[i].match_test_generics(sp, params.m_types[i], this->callback_resolve_infer(), cb); + if( fail ) { + DEBUG("- Failed to match"); + return false; + } + for(const auto& ty : impl_params) + assert( ty ); + + auto monomorph = [&](const auto& gt)->const auto& { + const auto& ge = gt.m_data.as_Generic(); + assert( ge.binding < impl_params.size() ); + return *impl_params[ge.binding]; + }; + auto args_mono = monomorphise_path_params_with(sp, impl.m_trait_args, monomorph, false); + + // TODO: Check bounds + for(const auto& bound : impl.m_params.m_bounds) + { + TU_MATCH(::HIR::GenericBound, (bound), (be), + (Lifetime, + ), + (TypeLifetime, + ), + (TraitBound, + DEBUG("Check bound " << be.type << " : " << be.trait); + auto real_type = monomorphise_type_with(sp, be.type, monomorph, false); + auto real_trait = monomorphise_traitpath_with(sp, be.trait, monomorph, false); + for(auto& ab : real_trait.m_type_bounds) { + ab.second = this->expand_associated_types(sp, mv$(ab.second)); + } + DEBUG("- " << real_type << " : " << real_trait); + auto rv = this->find_trait_impls(sp, real_trait.m_path.m_path, real_trait.m_path.m_params, real_type, [&](const auto& a, const auto& t) { + for(const auto& assoc_bound : real_trait.m_type_bounds) { + auto it = t.find(assoc_bound.first); + if( it == t.end() ) + { + auto ty = ::HIR::TypeRef(::HIR::Path(::HIR::Path::Data::Data_UfcsKnown { box$(real_type.clone()), real_trait.m_path.clone(), assoc_bound.first, {} })); + auto ty2 = this->expand_associated_types(sp, mv$(ty)); + + if( ty2 == assoc_bound.second ) { + return true; + } + TODO(sp, "Check type bound (fuzz) " << ty2 << " = " << assoc_bound.second); + } + else { + if( it->second == assoc_bound.second ) { + return true; + } + TODO(sp, "Check type bound (fuzz) " << it->second << " = " << assoc_bound.second); + } + } + return true; + }); + if( !rv ) { + // false = keep going + return false; + } + ), + (TypeEquality, + TODO(sp, "Check bound " << be.type << " = " << be.other_type); + ) + ) + } + + ::std::map< ::std::string, ::HIR::TypeRef> types; + for( const auto& aty : impl.m_types ) + { + types.insert( ::std::make_pair(aty.first, this->expand_associated_types(sp, monomorphise_type_with(sp, aty.second, monomorph))) ); + } + + DEBUG("[find_trait_impls_crate] callback(args=" << args_mono << ", assoc={" << types << "})"); + return callback(args_mono, types); } ); } @@ -1657,6 +1735,31 @@ bool typeck::TypecheckContext::trait_contains_method(const Span& sp, const ::HIR } return false; } +bool typeck::TypecheckContext::trait_contains_type(const Span& sp, const ::HIR::GenericPath& trait_path, const ::HIR::Trait& trait_ptr, const ::std::string& name, ::HIR::GenericPath& out_path) const +{ + auto it = trait_ptr.m_types.find(name); + if( it != trait_ptr.m_types.end() ) { + out_path = trait_path.clone(); + return true; + } + + auto monomorph = [&](const auto& gt)->const auto& { + const auto& ge = gt.m_data.as_Generic(); + assert(ge.binding < 256); + assert(ge.binding < trait_path.m_params.m_types.size()); + return trait_path.m_params.m_types[ge.binding]; + }; + // TODO: Prevent infinite recursion + for(const auto& st : trait_ptr.m_parent_traits) + { + auto& st_ptr = this->m_crate.get_trait_by_path(sp, st.m_path.m_path); + if( trait_contains_type(sp, st.m_path, st_ptr, name, out_path) ) { + out_path.m_params = monomorphise_path_params_with(sp, mv$(out_path.m_params), monomorph, false); + return true; + } + } + return false; +} @@ -1675,8 +1778,9 @@ const ::HIR::TypeRef* typeck::TypecheckContext::autoderef(const Span& sp, const return &tmp_type; ) else { - // TODO: Search for a Deref impl - bool succ = this->find_trait_impls(this->m_crate.get_lang_item_path(sp, "deref"), ty, [&](const auto& args) { + bool succ = this->find_trait_impls(sp, this->m_crate.get_lang_item_path(sp, "deref"), ::HIR::PathParams {}, ty, [&](const auto& args, const auto& types) { + assert(args.m_types.size() == 0); + // TODO: Use `types` return true; }); if( succ ) { @@ -1838,7 +1942,8 @@ bool typeck::TypecheckContext::find_method(const Span& sp, const ::HIR::TypeRef& 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; }) ) { + // TODO: Need a "don't care" marker for the PathParams + if( find_trait_impls_crate(sp, *trait_ref.first, ::HIR::PathParams{}, ty, [](const auto&,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() ), |