summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2016-06-12 21:39:16 +0800
committerJohn Hodge <tpg@mutabah.net>2016-06-12 21:39:16 +0800
commit1e702d1fb104b6b4a040945d8b18a7afdb216b5e (patch)
tree381216429f76b11a71b00d463eedab3e06d7fe00
parentb182c3780e0398921372ecef6780de3d0f89b016 (diff)
downloadmrust-1e702d1fb104b6b4a040945d8b18a7afdb216b5e.tar.gz
HIR Typecheck - Rework handling of trait impl searching
-rw-r--r--src/hir/path.cpp24
-rw-r--r--src/hir/path.hpp2
-rw-r--r--src/hir/type.cpp14
-rw-r--r--src/hir/type.hpp2
-rw-r--r--src/hir_typeck/expr.cpp133
-rw-r--r--src/hir_typeck/expr.hpp20
-rw-r--r--src/hir_typeck/expr_context.cpp465
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() ),