summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2016-07-03 19:56:24 +0800
committerJohn Hodge <tpg@mutabah.net>2016-07-03 19:56:24 +0800
commit909257298c23f449491c57d8f4b91bfc6a7b077b (patch)
tree2acddca3f3316cd60392ac7d9fe96c02b68d2016 /src
parent08290af3aa179c24e34b6d516265c1b789514893 (diff)
downloadmrust-909257298c23f449491c57d8f4b91bfc6a7b077b.tar.gz
HIR Typecheck - Move TraitResolve to helpers.cpp
Diffstat (limited to 'src')
-rw-r--r--src/hir_typeck/expr_context.cpp903
-rw-r--r--src/hir_typeck/expr_cs.cpp81
-rw-r--r--src/hir_typeck/expr_simple.hpp62
-rw-r--r--src/hir_typeck/helpers.cpp908
-rw-r--r--src/hir_typeck/helpers.hpp65
5 files changed, 981 insertions, 1038 deletions
diff --git a/src/hir_typeck/expr_context.cpp b/src/hir_typeck/expr_context.cpp
index 3c81dd04..1ef16035 100644
--- a/src/hir_typeck/expr_context.cpp
+++ b/src/hir_typeck/expr_context.cpp
@@ -1101,906 +1101,3 @@ void typeck::TypecheckContext::apply_equality(const Span& sp, const ::HIR::TypeR
}
}
-
-// -------------------------------------------------------------------------------------------------------------------
-//
-// -------------------------------------------------------------------------------------------------------------------
-bool typeck::TraitResolution::iterate_bounds( ::std::function<bool(const ::HIR::GenericBound&)> cb) const
-{
- const ::HIR::GenericParams* v[2] = { m_item_params, m_impl_params };
- for(auto p : v)
- {
- if( !p ) continue ;
- for(const auto& b : p->m_bounds)
- if(cb(b)) return true;
- }
- return false;
-}
-bool typeck::TraitResolution::find_trait_impls(const Span& sp,
- const ::HIR::SimplePath& trait, const ::HIR::PathParams& params,
- const ::HIR::TypeRef& type,
- t_cb_trait_impl callback
- ) const
-{
- TRACE_FUNCTION_F("trait = " << trait << ", type = " << type);
-
- // Closures are magical. They're unnamable and all trait impls come from within the compiler
- TU_IFLET(::HIR::TypeRef::Data, type.m_data, Closure, e,
- 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 ) {
- 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)) );
- ::std::map< ::std::string, ::HIR::TypeRef> types;
- types.insert( ::std::make_pair( "Output", e.m_rettype->clone() ) );
- return callback( pp, types );
- }
- else {
- return false;
- }
- )
-
- // 1. Search generic params
- if( find_trait_impls_bound(sp, trait, params, type, callback) )
- return true;
- // 2. Search crate-level impls
- return find_trait_impls_crate(sp, trait, params, type, callback);
-}
-
-// -------------------------------------------------------------------------------------------------------------------
-//
-// -------------------------------------------------------------------------------------------------------------------
-::HIR::TypeRef typeck::TraitResolution::expand_associated_types(const Span& sp, ::HIR::TypeRef input) const
-{
- TRACE_FUNCTION_F(input);
- TU_MATCH(::HIR::TypeRef::Data, (input.m_data), (e),
- (Infer,
- auto& ty = this->m_ivars.get_type(input);
- if( ty != input ) {
- input = expand_associated_types(sp, ty.clone());
- return input;
- }
- else {
- }
- return input;
- ),
- (Diverge,
- ),
- (Primitive,
- ),
- (Path,
- TU_MATCH(::HIR::Path::Data, (e.path.m_data), (e2),
- (Generic,
- for(auto& arg : e2.m_params.m_types)
- arg = expand_associated_types(sp, mv$(arg));
- ),
- (UfcsInherent,
- TODO(sp, "Path - UfcsInherent - " << e.path);
- ),
- (UfcsKnown,
- // - Only try resolving if the binding isn't known
- if( !e.binding.is_Unbound() )
- return input;
-
- DEBUG("Locating associated type for " << e.path);
-
- *e2.type = expand_associated_types(sp, mv$(*e2.type));
-
-
- // - If it's a closure, then the only trait impls are those generated by typeck
- TU_IFLET(::HIR::TypeRef::Data, e2.type->m_data, Closure, te,
- 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( e2.trait.m_path == trait_fn || e2.trait.m_path == trait_fn_mut || e2.trait.m_path == trait_fn_once ) {
- if( e2.item == "Output" ) {
- return te.m_rettype->clone();
- }
- else {
- ERROR(sp, E0000, "No associated type " << e2.item << " for trait " << e2.trait);
- }
- }
- else {
- ERROR(sp, E0000, "No implementation of " << e2.trait << " for " << *e2.type);
- }
- )
-
- // 1. Bounds
- bool rv;
- bool assume_opaque = true;
- rv = this->iterate_bounds([&](const auto& b) {
- TU_MATCH_DEF(::HIR::GenericBound, (b), (be),
- (
- ),
- (TraitBound,
- DEBUG("Trait bound - " << be.type << " : " << be.trait);
- // 1. Check if the type matches
- // - TODO: This should be a fuzzier match?
- if( be.type != *e2.type )
- return false;
- // 2. Check if the trait (or any supertrait) includes e2.trait
- if( be.trait.m_path == e2.trait ) {
- auto it = be.trait.m_type_bounds.find(e2.item);
- // 1. Check if the bounds include the desired item
- if( it == be.trait.m_type_bounds.end() ) {
- // If not, assume it's opaque and return as such
- // TODO: What happens if there's two bounds that overlap? 'F: FnMut<()>, F: FnOnce<(), Output=Bar>'
- DEBUG("Found impl for " << input << " but no bound on item, assuming opaque");
- }
- else {
- assume_opaque = false;
- input = it->second.clone();
- }
- return true;
- }
-
- bool found_supertrait = this->find_named_trait_in_trait(sp,
- 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);
- if( it != assoc.end() ) {
- assume_opaque = false;
- DEBUG("Found associated type " << input << " = " << it->second);
- input = it->second.clone();
- }
- return true;
- }
- );
- if( found_supertrait ) {
- auto it = be.trait.m_type_bounds.find(e2.item);
- // 1. Check if the bounds include the desired item
- if( it == be.trait.m_type_bounds.end() ) {
- // If not, assume it's opaque and return as such
- // TODO: What happens if there's two bounds that overlap? 'F: FnMut<()>, F: FnOnce<(), Output=Bar>'
- if( assume_opaque )
- DEBUG("Found impl for " << input << " but no bound on item, assuming opaque");
- }
- else {
- assume_opaque = false;
- input = it->second.clone();
- }
- return true;
- }
-
- // - Didn't match
- ),
- (TypeEquality,
- DEBUG("Equality - " << be.type << " = " << be.other_type);
- if( input == be.type ) {
- input = be.other_type.clone();
- return true;
- }
- )
- )
- return false;
- });
- if( rv ) {
- if( assume_opaque ) {
- 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;
- }
-
- // If the type of this UfcsKnown is ALSO a UfcsKnown - Check if it's bounded by this trait with equality
- // Use bounds on other associated types too (if `e2.type` was resolved to a fixed associated type)
- TU_IFLET(::HIR::TypeRef::Data, e2.type->m_data, Path, te_inner,
- TU_IFLET(::HIR::Path::Data, te_inner.path.m_data, UfcsKnown, pe_inner,
- // TODO: Search for equality bounds on this associated type (e3) that match the entire type (e2)
- // - Does simplification of complex associated types
- const auto& trait_ptr = this->m_crate.get_trait_by_path(sp, pe_inner.trait.m_path);
- const auto& assoc_ty = trait_ptr.m_types.at(pe_inner.item);
- DEBUG("TODO: Search bounds on associated type - " << assoc_ty.m_params.fmt_bounds());
-
- // Resolve where Self=e2.type, for the associated type check.
- auto cb_placeholders_type = [&](const auto& ty)->const auto&{
- TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Generic, e,
- if( e.binding == 0xFFFF )
- return *e2.type;
- else
- TODO(sp, "Handle type params when expanding associated bound (#" << e.binding << " " << e.name);
- )
- else {
- return ty;
- }
- };
- // Resolve where Self=pe_inner.type (i.e. for the trait this inner UFCS is on)
- auto cb_placeholders_trait = [&](const auto& ty)->const auto&{
- TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Generic, e,
- if( e.binding == 0xFFFF )
- return *pe_inner.type;
- else {
- // TODO: Look in pe_inner.trait.m_params
- TODO(sp, "Handle type params when expanding associated bound (#" << e.binding << " " << e.name);
- }
- )
- else {
- return ty;
- }
- };
- for(const auto& bound : assoc_ty.m_params.m_bounds)
- {
- TU_MATCH_DEF(::HIR::GenericBound, (bound), (be),
- (
- ),
- (TraitBound,
- // If the bound is for Self and the outer trait
- // - TODO: Parameters?
- if( be.type == ::HIR::TypeRef("Self", 0xFFFF) && be.trait.m_path == e2.trait ) {
- auto it = be.trait.m_type_bounds.find( e2.item );
- if( it != be.trait.m_type_bounds.end() ) {
- if( monomorphise_type_needed(it->second) ) {
- input = monomorphise_type_with(sp, it->second, cb_placeholders_trait);
- }
- else {
- input = it->second.clone();
- }
- input = this->expand_associated_types(sp, mv$(input));
- return input;
- }
- }
- ),
- (TypeEquality,
- // IF: bound's type matches the input, replace with bounded equality
- // `<Self::IntoIter as Iterator>::Item = Self::Item`
- 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) ) {
- input = monomorphise_type_with(sp, be.other_type, cb_placeholders_trait);
- }
- else {
- input = be.other_type.clone();
- }
- input = this->expand_associated_types(sp, mv$(input));
- return input;
- }
- )
- )
- }
- DEBUG("e2 = " << *e2.type << ", input = " << input);
- )
- )
-
- // 2. Crate-level impls
- // 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);
-
- 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->m_ivars.type_contains_ivars(input) ) {
- e.binding = ::HIR::TypeRef::TypePathBinding::make_Opaque({});
- }
-
- DEBUG("Couldn't resolve associated type for " << input);
- ),
- (UfcsUnknown,
- BUG(sp, "Encountered UfcsUnknown");
- )
- )
- ),
- (Generic,
- ),
- (TraitObject,
- // Recurse?
- ),
- (Array,
- *e.inner = expand_associated_types(sp, mv$(*e.inner));
- ),
- (Slice,
- *e.inner = expand_associated_types(sp, mv$(*e.inner));
- ),
- (Tuple,
- for(auto& sub : e) {
- sub = expand_associated_types(sp, mv$(sub));
- }
- ),
- (Borrow,
- *e.inner = expand_associated_types(sp, mv$(*e.inner));
- ),
- (Pointer,
- *e.inner = expand_associated_types(sp, mv$(*e.inner));
- ),
- (Function,
- // Recurse?
- ),
- (Closure,
- // Recurse?
- )
- )
- return input;
-}
-
-
-// -------------------------------------------------------------------------------------------------------------------
-//
-// -------------------------------------------------------------------------------------------------------------------
-bool typeck::TraitResolution::find_named_trait_in_trait(const Span& sp,
- 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
- ) const
-{
- TRACE_FUNCTION_F(des << " from " << trait_path << pp);
- if( pp.m_types.size() != trait_ptr.m_params.m_types.size() ) {
- BUG(sp, "Incorrect number of parameters for trait");
- }
- for( const auto& pt : trait_ptr.m_parent_traits )
- {
- auto pt_mono = monomorphise_traitpath_with(sp, pt, [&](const auto& gt)->const auto& {
- const auto& ge = gt.m_data.as_Generic();
- if( ge.binding == 0xFFFF ) {
- return target_type;
- }
- else {
- if( ge.binding >= pp.m_types.size() )
- BUG(sp, "find_named_trait_in_trait - Generic #" << ge.binding << " " << ge.name << " out of range");
- return pp.m_types[ge.binding];
- }
- }, false);
-
- DEBUG(pt << " => " << pt_mono);
- if( pt.m_path.m_path == des ) {
- callback( pt_mono.m_path.m_params, pt_mono.m_type_bounds );
- return true;
- }
- }
- return false;
-}
-bool typeck::TraitResolution::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->m_ivars.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,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::TraitResolution::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() )
- return this->m_ivars.get_type(ty);
- else
- return ty;
- },
- [&](const auto& impl) {
- DEBUG("[find_trait_impls_crate] Found impl" << impl.m_params.fmt_args() << " " << trait << impl.m_trait_args << " for " << impl.m_type);
- // Compare with `params`
- auto match = ::HIR::Compare::Equal;
- ::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 ) {
- // Strict equality is OK, as all types should be sane
- // - TODO: What if there's an un-expanded associated?
- match = ::HIR::Compare::Unequal;
- }
- else {
- }
- };
- assert( impl.m_trait_args.m_types.size() == params.m_types.size() );
- match &= impl.m_type.match_test_generics_fuzz(sp, type , this->m_ivars.callback_resolve_infer(), cb);
- for(unsigned int i = 0; i < impl.m_trait_args.m_types.size(); i ++)
- match &= impl.m_trait_args.m_types[i].match_test_generics_fuzz(sp, params.m_types[i], this->m_ivars.callback_resolve_infer(), cb);
- if( match == ::HIR::Compare::Unequal ) {
- DEBUG("- Failed to match parameters - " << impl.m_trait_args << " != " << params);
- 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;
- }
- this->m_ivars.dump();
- TODO(sp, "Check type bound (fuzz) " << ty2 << " = " << assoc_bound.second);
- }
- else {
- if( this->m_ivars.get_type(it->second) == assoc_bound.second ) {
- return true;
- }
- this->m_ivars.dump();
- 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 << "})");
- //if( match == ::HIR::Compare::Fuzzy ) {
- // TODO(sp, "- Pass on fuzzy match status");
- //}
- return callback(args_mono, types/*, (match == ::HIR::Compare::Fuzzy)*/);
- }
- );
-}
-
-bool typeck::TraitResolution::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
-{
- auto it = trait_ptr.m_values.find(name);
- if( it != trait_ptr.m_values.end() ) {
- if( it->second.is_Function() ) {
- out_path = trait_path.clone();
- return true;
- }
- }
-
- // 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_method(sp, st.m_path, st_ptr, name, out_path) ) {
- out_path.m_params = monomorphise_path_params_with(sp, mv$(out_path.m_params), [&](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];
- }, false);
- return true;
- }
- }
- return false;
-}
-bool typeck::TraitResolution::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;
-}
-
-
-
-// -------------------------------------------------------------------------------------------------------------------
-//
-// -------------------------------------------------------------------------------------------------------------------
-const ::HIR::TypeRef* typeck::TraitResolution::autoderef(const Span& sp, const ::HIR::TypeRef& ty, ::HIR::TypeRef& tmp_type) const
-{
- TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Borrow, e,
- DEBUG("Deref " << ty << " into " << *e.inner);
- return &*e.inner;
- )
- else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, e,
- DEBUG("Deref " << ty << " into [" << *e.inner << "]");
- tmp_type = ::HIR::TypeRef::new_slice( e.inner->clone() );
- return &tmp_type;
- )
- else {
- 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 ) {
- TODO(sp, "Found a Deref impl for " << ty << ", use the output of it");
- }
- else {
- return nullptr;
- }
- }
-}
-unsigned int typeck::TraitResolution::autoderef_find_method(const Span& sp, const HIR::t_trait_list& traits, const ::HIR::TypeRef& top_ty, const ::std::string& method_name, /* Out -> */::HIR::Path& fcn_path) const
-{
- unsigned int deref_count = 0;
- ::HIR::TypeRef tmp_type; // Temporary type used for handling Deref
- const auto* current_ty = &top_ty;
- TU_IFLET(::HIR::TypeRef::Data, this->m_ivars.get_type(top_ty).m_data, Borrow, e,
- current_ty = &*e.inner;
- deref_count += 1;
- )
-
- do {
- const auto& ty = this->m_ivars.get_type(*current_ty);
- if( ty.m_data.is_Infer() ) {
- return ~0u;
- }
-
- if( this->find_method(sp, traits, ty, method_name, fcn_path) ) {
- return deref_count;
- }
-
- // 3. Dereference and try again
- deref_count += 1;
- current_ty = this->autoderef(sp, ty, tmp_type);
- } while( current_ty );
-
- TU_IFLET(::HIR::TypeRef::Data, this->m_ivars.get_type(top_ty).m_data, Borrow, e,
- const auto& ty = this->m_ivars.get_type(top_ty);
-
- if( find_method(sp, traits, ty, method_name, fcn_path) ) {
- return 0;
- }
- )
-
- // Dereference failed! This is a hard error (hitting _ is checked above and returns ~0)
- this->m_ivars.dump();
- TODO(sp, "Error when no method could be found, but type is known - (: " << top_ty << ")." << method_name);
-}
-
-bool typeck::TraitResolution::find_method(const Span& sp, const HIR::t_trait_list& traits, const ::HIR::TypeRef& ty, const ::std::string& method_name, /* Out -> */::HIR::Path& fcn_path) const
-{
- TRACE_FUNCTION_F("ty=" << ty << ", name=" << method_name);
- // 1. Search generic bounds for a match
- const ::HIR::GenericParams* v[2] = { m_item_params, m_impl_params };
- for(auto p : v)
- {
- if( !p ) continue ;
- for(const auto& b : p->m_bounds)
- {
- TU_IFLET(::HIR::GenericBound, b, TraitBound, e,
- DEBUG("Bound " << e.type << " : " << e.trait.m_path);
- // TODO: Match using _ replacement
- if( e.type != ty )
- continue ;
-
- // - Bound's type matches, check if the bounded trait has the method we're searching for
- // > TODO: Search supertraits too
- DEBUG("- Matches " << ty);
- ::HIR::GenericPath final_trait_path;
- assert(e.trait.m_trait_ptr);
- if( !this->trait_contains_method(sp, e.trait.m_path, *e.trait.m_trait_ptr, method_name, final_trait_path) )
- continue ;
- DEBUG("- Found trait " << final_trait_path);
-
- // Found the method, return the UFCS path for it
- fcn_path = ::HIR::Path( ::HIR::Path::Data::make_UfcsKnown({
- box$( ty.clone() ),
- mv$(final_trait_path),
- method_name,
- {}
- }) );
- return true;
- )
- }
- }
-
- TU_IFLET(::HIR::TypeRef::Data, ty.m_data, TraitObject, e,
- // TODO: This _Should_ be set, but almost needs a pass?
- //assert( e.m_trait.m_trait_ptr );
- //const auto& trait = *e.m_trait.m_trait_ptr;
- const auto& trait = this->m_crate.get_trait_by_path(sp, e.m_trait.m_path.m_path);
- auto it = trait.m_values.find( method_name );
- if( it != trait.m_values.end() )
- {
- if( it->second.is_Function() ) {
- fcn_path = ::HIR::Path( ::HIR::Path::Data::Data_UfcsKnown({
- box$( ty.clone() ),
- e.m_trait.m_path.clone(),
- method_name,
- {}
- }) );
- return true;
- }
- }
- )
-
- TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Generic, e,
- // No match, keep trying.
- )
- else if( ty.m_data.is_Path() && ty.m_data.as_Path().path.m_data.is_UfcsKnown() )
- {
- const auto& e = ty.m_data.as_Path().path.m_data.as_UfcsKnown();
- // UFCS known - Assuming that it's reached the maximum resolvable level (i.e. a type within is generic), search for trait bounds on the type
- const auto& trait = this->m_crate.get_trait_by_path(sp, e.trait.m_path);
- const auto& assoc_ty = trait.m_types.at( e.item );
- // NOTE: The bounds here have 'Self' = the type
- for(const auto& bound : assoc_ty.m_params.m_bounds )
- {
- TU_IFLET(::HIR::GenericBound, bound, TraitBound, be,
- assert(be.trait.m_trait_ptr);
- ::HIR::GenericPath final_trait_path;
- if( !this->trait_contains_method(sp, be.trait.m_path, *be.trait.m_trait_ptr, method_name, final_trait_path) )
- continue ;
- DEBUG("- Found trait " << final_trait_path);
-
- // Found the method, return the UFCS path for it
- fcn_path = ::HIR::Path( ::HIR::Path::Data::make_UfcsKnown({
- box$( ty.clone() ),
- mv$(final_trait_path),
- method_name,
- {}
- }) );
- return true;
- )
- }
- }
- else {
- // 2. Search for inherent methods
- for(const auto& impl : m_crate.m_type_impls)
- {
- if( impl.matches_type(ty) ) {
- auto it = impl.m_methods.find( method_name );
- if( it == impl.m_methods.end() )
- continue ;
- DEBUG("Matching `impl" << impl.m_params.fmt_args() << " " << impl.m_type << "`"/* << " - " << top_ty*/);
- fcn_path = ::HIR::Path( ::HIR::Path::Data::make_UfcsInherent({
- box$(ty.clone()),
- method_name,
- {}
- }) );
- return true;
- }
- }
- // 3. Search for trait methods (using currently in-scope traits)
- for(const auto& trait_ref : ::reverse(traits))
- {
- if( trait_ref.first == nullptr )
- break;
-
- // TODO: Search supertraits too
- auto it = trait_ref.second->m_values.find(method_name);
- if( it == trait_ref.second->m_values.end() )
- continue ;
- if( !it->second.is_Function() )
- continue ;
- DEBUG("Search for impl of " << *trait_ref.first);
- // 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 << " (" /*<< m_ivars.fmt_type(*trait_ref.first)*/ << ") for " << ty << " ("<<m_ivars.fmt_type(ty)<<")");
- fcn_path = ::HIR::Path( ::HIR::Path::Data::make_UfcsKnown({
- box$( ty.clone() ),
- trait_ref.first->clone(),
- method_name,
- {}
- }) );
- return true;
- }
- }
- }
-
- return false;
-}
-
-unsigned int typeck::TraitResolution::autoderef_find_field(const Span& sp, const ::HIR::TypeRef& top_ty, const ::std::string& field_name, /* Out -> */::HIR::TypeRef& field_type) const
-{
- unsigned int deref_count = 0;
- ::HIR::TypeRef tmp_type; // Temporary type used for handling Deref
- const auto* current_ty = &top_ty;
- TU_IFLET(::HIR::TypeRef::Data, this->m_ivars.get_type(top_ty).m_data, Borrow, e,
- current_ty = &*e.inner;
- deref_count += 1;
- )
-
- do {
- const auto& ty = this->m_ivars.get_type(*current_ty);
- if( ty.m_data.is_Infer() ) {
- return ~0u;
- }
-
- if( this->find_field(sp, ty, field_name, field_type) ) {
- return deref_count;
- }
-
- // 3. Dereference and try again
- deref_count += 1;
- current_ty = this->autoderef(sp, ty, tmp_type);
- } while( current_ty );
-
- TU_IFLET(::HIR::TypeRef::Data, this->m_ivars.get_type(top_ty).m_data, Borrow, e,
- const auto& ty = this->m_ivars.get_type(top_ty);
-
- if( find_field(sp, ty, field_name, field_type) ) {
- return 0;
- }
- )
-
- // Dereference failed! This is a hard error (hitting _ is checked above and returns ~0)
- this->m_ivars.dump();
- TODO(sp, "Error when no field could be found, but type is known - (: " << top_ty << ")." << field_name);
-}
-bool typeck::TraitResolution::find_field(const Span& sp, const ::HIR::TypeRef& ty, const ::std::string& name, /* Out -> */::HIR::TypeRef& field_ty) const
-{
- TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Path, e,
- TU_MATCH(::HIR::TypeRef::TypePathBinding, (e.binding), (be),
- (Unbound,
- // Wut?
- TODO(sp, "Handle TypePathBinding::Unbound - " << ty);
- ),
- (Opaque,
- // Ignore, no fields on an opaque
- ),
- (Struct,
- // Has fields!
- const auto& str = *be;
- const auto& params = e.path.m_data.as_Generic().m_params;
- auto monomorph = [&](const auto& gt)->const auto& {
- const auto& ge = gt.m_data.as_Generic();
- if( ge.binding == 0xFFFF )
- TODO(sp, "Monomorphise struct field types (Self) - " << gt);
- else if( ge.binding < 256 ) {
- assert(ge.binding < params.m_types.size());
- return params.m_types[ge.binding];
- }
- else {
- BUG(sp, "function-level param encountered in struct field");
- }
- return gt;
- };
- TU_MATCH(::HIR::Struct::Data, (str.m_data), (se),
- (Unit,
- // No fields on a unit struct
- ),
- (Tuple,
- for( unsigned int i = 0; i < se.size(); i ++ )
- {
- // TODO: Privacy
- if( FMT(i) == name ) {
- field_ty = monomorphise_type_with(sp, se[i].ent, monomorph);
- return true;
- }
- }
- ),
- (Named,
- for( const auto& fld : se )
- {
- // TODO: Privacy
- if( fld.first == name ) {
- field_ty = monomorphise_type_with(sp, fld.second.ent, monomorph);
- return true;
- }
- }
- )
- )
- ),
- (Enum,
- // No fields on enums either
- )
- )
- )
- else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Tuple, e,
- for( unsigned int i = 0; i < e.size(); i ++ )
- {
- if( FMT(i) == name ) {
- field_ty = e[i].clone();
- return true;
- }
- }
- )
- else {
- }
- return false;
-}
-
-
diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp
index d306f89e..4933f54f 100644
--- a/src/hir_typeck/expr_cs.cpp
+++ b/src/hir_typeck/expr_cs.cpp
@@ -41,11 +41,10 @@ struct Context
};
const ::HIR::Crate& m_crate;
- const ::HIR::GenericParams* m_impl_params;
- const ::HIR::GenericParams* m_item_params;
::std::vector<Binding> m_bindings;
HMTypeInferrence m_ivars;
+ TraitResolution m_resolve;
::std::vector<Coercion> link_coerce;
::std::vector<Associated> link_assoc;
@@ -54,8 +53,7 @@ struct Context
Context(const ::HIR::Crate& crate, const ::HIR::GenericParams* impl_params, const ::HIR::GenericParams* item_params):
m_crate(crate),
- m_impl_params( impl_params ),
- m_item_params( item_params )
+ m_resolve(m_ivars, crate, impl_params, item_params)
{
}
@@ -66,7 +64,9 @@ struct Context
return link_coerce.size() > 0 || link_assoc.size() > 0 || to_visit.size() > 0;
}
- void add_ivars(::HIR::TypeRef& ty);
+ void add_ivars(::HIR::TypeRef& ty) {
+ m_ivars.add_ivars(ty);
+ }
// - Equate two types, with no possibility of coercion
// > Errors if the types are incompatible.
// > Forces types if one side is an infer
@@ -88,7 +88,9 @@ struct Context
const ::HIR::TypeRef& get_type(const ::HIR::TypeRef& ty) const { return m_ivars.get_type(ty); }
private:
- void add_ivars_params(::HIR::PathParams& params);
+ void add_ivars_params(::HIR::PathParams& params) {
+ m_ivars.add_ivars_params(params);
+ }
};
static void fix_param_count(const Span& sp, Context& context, const ::HIR::Path& path, const ::HIR::GenericParams& param_defs, ::HIR::PathParams& params);
@@ -1183,73 +1185,6 @@ void Context::dump() const {
DEBUG(&v << " " << typeid(*v).name());
}
}
-void Context::add_ivars(::HIR::TypeRef& ty) {
- TU_MATCH(::HIR::TypeRef::Data, (ty.m_data), (e),
- (Infer,
- if( e.index == ~0u ) {
- e.index = this->m_ivars.new_ivar();
- this->m_ivars.get_type(ty).m_data.as_Infer().ty_class = e.ty_class;
- }
- ),
- (Diverge,
- ),
- (Primitive,
- ),
- (Path,
- // Iterate all arguments
- TU_MATCH(::HIR::Path::Data, (e.path.m_data), (e2),
- (Generic,
- this->add_ivars_params(e2.m_params);
- ),
- (UfcsKnown,
- this->add_ivars(*e2.type);
- this->add_ivars_params(e2.trait.m_params);
- this->add_ivars_params(e2.params);
- ),
- (UfcsUnknown,
- this->add_ivars(*e2.type);
- this->add_ivars_params(e2.params);
- ),
- (UfcsInherent,
- this->add_ivars(*e2.type);
- this->add_ivars_params(e2.params);
- )
- )
- ),
- (Generic,
- ),
- (TraitObject,
- // Iterate all paths
- ),
- (Array,
- add_ivars(*e.inner);
- ),
- (Slice,
- add_ivars(*e.inner);
- ),
- (Tuple,
- for(auto& ty : e)
- add_ivars(ty);
- ),
- (Borrow,
- add_ivars(*e.inner);
- ),
- (Pointer,
- add_ivars(*e.inner);
- ),
- (Function,
- // No ivars allowed
- // TODO: Check?
- ),
- (Closure,
- // Shouldn't be possible
- )
- )
-}
-void Context::add_ivars_params(::HIR::PathParams& params) {
- for(auto& arg : params.m_types)
- add_ivars(arg);
-}
void Context::equate_types(const Span& sp, const ::HIR::TypeRef& li, const ::HIR::TypeRef& ri) {
// Instantly apply equality
diff --git a/src/hir_typeck/expr_simple.hpp b/src/hir_typeck/expr_simple.hpp
index 9f9585a5..1268918b 100644
--- a/src/hir_typeck/expr_simple.hpp
+++ b/src/hir_typeck/expr_simple.hpp
@@ -13,68 +13,6 @@ namespace typeck {
extern void check_type_class_primitive(const Span& sp, const ::HIR::TypeRef& type, ::HIR::InferClass ic, ::HIR::CoreType ct);
-class TraitResolution
-{
- const HMTypeInferrence& m_ivars;
-
- const ::HIR::Crate& m_crate;
- const ::HIR::GenericParams* m_impl_params;
- const ::HIR::GenericParams* m_item_params;
-
-public:
- TraitResolution(const HMTypeInferrence& ivars, const ::HIR::Crate& crate, const ::HIR::GenericParams* impl_params, const ::HIR::GenericParams* item_params):
- m_ivars(ivars),
- m_crate(crate),
- m_impl_params( impl_params ),
- m_item_params( item_params )
- {
- }
-
- typedef ::std::function<bool(const ::HIR::PathParams&, const ::std::map< ::std::string,::HIR::TypeRef>&)> t_cb_trait_impl;
-
- /// Check if a trait bound applies, using the passed function to expand Generic/Infer types
- bool check_trait_bound(const Span& sp, const ::HIR::TypeRef& type, const ::HIR::GenericPath& trait, t_cb_generic placeholder) const;
-
- /// Expand any located associated types in the input, operating in-place and returning the result
- ::HIR::TypeRef expand_associated_types(const Span& sp, ::HIR::TypeRef input) const;
-
- /// 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 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::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::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 Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& type, t_cb_trait_impl callback) const;
-
- /// Locate the named method by applying auto-dereferencing.
- /// \return Number of times deref was applied (or ~0 if _ was hit)
- unsigned int autoderef_find_method(const Span& sp, const HIR::t_trait_list& traits, const ::HIR::TypeRef& top_ty, const ::std::string& method_name, /* Out -> */::HIR::Path& fcn_path) const;
- /// Locate the named field by applying auto-dereferencing.
- /// \return Number of times deref was applied (or ~0 if _ was hit)
- unsigned int autoderef_find_field(const Span& sp, const ::HIR::TypeRef& top_ty, const ::std::string& name, /* Out -> */::HIR::TypeRef& field_type) const;
-
- /// Apply an automatic dereference
- const ::HIR::TypeRef* autoderef(const Span& sp, const ::HIR::TypeRef& ty, ::HIR::TypeRef& tmp_type) const;
-
-private:
- bool find_method(const Span& sp, const HIR::t_trait_list& traits, const ::HIR::TypeRef& ty, const ::std::string& method_name, /* Out -> */::HIR::Path& fcn_path) const;
- bool find_field(const Span& sp, const ::HIR::TypeRef& ty, const ::std::string& name, /* Out -> */::HIR::TypeRef& field_type) 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;
-};
-
class TypecheckContext
{
struct Variable
diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp
index e560d2e7..e7d20223 100644
--- a/src/hir_typeck/helpers.cpp
+++ b/src/hir_typeck/helpers.cpp
@@ -807,3 +807,911 @@ bool HMTypeInferrence::types_equal(const ::HIR::TypeRef& rl, const ::HIR::TypeRe
)
throw "";
}
+
+// -------------------------------------------------------------------------------------------------------------------
+//
+// -------------------------------------------------------------------------------------------------------------------
+
+
+// -------------------------------------------------------------------------------------------------------------------
+//
+// -------------------------------------------------------------------------------------------------------------------
+bool TraitResolution::iterate_bounds( ::std::function<bool(const ::HIR::GenericBound&)> cb) const
+{
+ const ::HIR::GenericParams* v[2] = { m_item_params, m_impl_params };
+ for(auto p : v)
+ {
+ if( !p ) continue ;
+ for(const auto& b : p->m_bounds)
+ if(cb(b)) return true;
+ }
+ return false;
+}
+bool TraitResolution::find_trait_impls(const Span& sp,
+ const ::HIR::SimplePath& trait, const ::HIR::PathParams& params,
+ const ::HIR::TypeRef& type,
+ t_cb_trait_impl callback
+ ) const
+{
+ TRACE_FUNCTION_F("trait = " << trait << ", type = " << type);
+
+ // Closures are magical. They're unnamable and all trait impls come from within the compiler
+ TU_IFLET(::HIR::TypeRef::Data, type.m_data, Closure, e,
+ 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 ) {
+ 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)) );
+ ::std::map< ::std::string, ::HIR::TypeRef> types;
+ types.insert( ::std::make_pair( "Output", e.m_rettype->clone() ) );
+ return callback( pp, types );
+ }
+ else {
+ return false;
+ }
+ )
+
+ // 1. Search generic params
+ if( find_trait_impls_bound(sp, trait, params, type, callback) )
+ return true;
+ // 2. Search crate-level impls
+ return find_trait_impls_crate(sp, trait, params, type, callback);
+}
+
+// -------------------------------------------------------------------------------------------------------------------
+//
+// -------------------------------------------------------------------------------------------------------------------
+::HIR::TypeRef TraitResolution::expand_associated_types(const Span& sp, ::HIR::TypeRef input) const
+{
+ TRACE_FUNCTION_F(input);
+ TU_MATCH(::HIR::TypeRef::Data, (input.m_data), (e),
+ (Infer,
+ auto& ty = this->m_ivars.get_type(input);
+ if( ty != input ) {
+ input = expand_associated_types(sp, ty.clone());
+ return input;
+ }
+ else {
+ }
+ return input;
+ ),
+ (Diverge,
+ ),
+ (Primitive,
+ ),
+ (Path,
+ TU_MATCH(::HIR::Path::Data, (e.path.m_data), (e2),
+ (Generic,
+ for(auto& arg : e2.m_params.m_types)
+ arg = expand_associated_types(sp, mv$(arg));
+ ),
+ (UfcsInherent,
+ TODO(sp, "Path - UfcsInherent - " << e.path);
+ ),
+ (UfcsKnown,
+ // - Only try resolving if the binding isn't known
+ if( !e.binding.is_Unbound() )
+ return input;
+
+ DEBUG("Locating associated type for " << e.path);
+
+ *e2.type = expand_associated_types(sp, mv$(*e2.type));
+
+
+ // - If it's a closure, then the only trait impls are those generated by typeck
+ TU_IFLET(::HIR::TypeRef::Data, e2.type->m_data, Closure, te,
+ 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( e2.trait.m_path == trait_fn || e2.trait.m_path == trait_fn_mut || e2.trait.m_path == trait_fn_once ) {
+ if( e2.item == "Output" ) {
+ return te.m_rettype->clone();
+ }
+ else {
+ ERROR(sp, E0000, "No associated type " << e2.item << " for trait " << e2.trait);
+ }
+ }
+ else {
+ ERROR(sp, E0000, "No implementation of " << e2.trait << " for " << *e2.type);
+ }
+ )
+
+ // 1. Bounds
+ bool rv;
+ bool assume_opaque = true;
+ rv = this->iterate_bounds([&](const auto& b) {
+ TU_MATCH_DEF(::HIR::GenericBound, (b), (be),
+ (
+ ),
+ (TraitBound,
+ DEBUG("Trait bound - " << be.type << " : " << be.trait);
+ // 1. Check if the type matches
+ // - TODO: This should be a fuzzier match?
+ if( be.type != *e2.type )
+ return false;
+ // 2. Check if the trait (or any supertrait) includes e2.trait
+ if( be.trait.m_path == e2.trait ) {
+ auto it = be.trait.m_type_bounds.find(e2.item);
+ // 1. Check if the bounds include the desired item
+ if( it == be.trait.m_type_bounds.end() ) {
+ // If not, assume it's opaque and return as such
+ // TODO: What happens if there's two bounds that overlap? 'F: FnMut<()>, F: FnOnce<(), Output=Bar>'
+ DEBUG("Found impl for " << input << " but no bound on item, assuming opaque");
+ }
+ else {
+ assume_opaque = false;
+ input = it->second.clone();
+ }
+ return true;
+ }
+
+ bool found_supertrait = this->find_named_trait_in_trait(sp,
+ 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);
+ if( it != assoc.end() ) {
+ assume_opaque = false;
+ DEBUG("Found associated type " << input << " = " << it->second);
+ input = it->second.clone();
+ }
+ return true;
+ }
+ );
+ if( found_supertrait ) {
+ auto it = be.trait.m_type_bounds.find(e2.item);
+ // 1. Check if the bounds include the desired item
+ if( it == be.trait.m_type_bounds.end() ) {
+ // If not, assume it's opaque and return as such
+ // TODO: What happens if there's two bounds that overlap? 'F: FnMut<()>, F: FnOnce<(), Output=Bar>'
+ if( assume_opaque )
+ DEBUG("Found impl for " << input << " but no bound on item, assuming opaque");
+ }
+ else {
+ assume_opaque = false;
+ input = it->second.clone();
+ }
+ return true;
+ }
+
+ // - Didn't match
+ ),
+ (TypeEquality,
+ DEBUG("Equality - " << be.type << " = " << be.other_type);
+ if( input == be.type ) {
+ input = be.other_type.clone();
+ return true;
+ }
+ )
+ )
+ return false;
+ });
+ if( rv ) {
+ if( assume_opaque ) {
+ 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;
+ }
+
+ // If the type of this UfcsKnown is ALSO a UfcsKnown - Check if it's bounded by this trait with equality
+ // Use bounds on other associated types too (if `e2.type` was resolved to a fixed associated type)
+ TU_IFLET(::HIR::TypeRef::Data, e2.type->m_data, Path, te_inner,
+ TU_IFLET(::HIR::Path::Data, te_inner.path.m_data, UfcsKnown, pe_inner,
+ // TODO: Search for equality bounds on this associated type (e3) that match the entire type (e2)
+ // - Does simplification of complex associated types
+ const auto& trait_ptr = this->m_crate.get_trait_by_path(sp, pe_inner.trait.m_path);
+ const auto& assoc_ty = trait_ptr.m_types.at(pe_inner.item);
+ DEBUG("TODO: Search bounds on associated type - " << assoc_ty.m_params.fmt_bounds());
+
+ // Resolve where Self=e2.type, for the associated type check.
+ auto cb_placeholders_type = [&](const auto& ty)->const auto&{
+ TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Generic, e,
+ if( e.binding == 0xFFFF )
+ return *e2.type;
+ else
+ TODO(sp, "Handle type params when expanding associated bound (#" << e.binding << " " << e.name);
+ )
+ else {
+ return ty;
+ }
+ };
+ // Resolve where Self=pe_inner.type (i.e. for the trait this inner UFCS is on)
+ auto cb_placeholders_trait = [&](const auto& ty)->const auto&{
+ TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Generic, e,
+ if( e.binding == 0xFFFF )
+ return *pe_inner.type;
+ else {
+ // TODO: Look in pe_inner.trait.m_params
+ TODO(sp, "Handle type params when expanding associated bound (#" << e.binding << " " << e.name);
+ }
+ )
+ else {
+ return ty;
+ }
+ };
+ for(const auto& bound : assoc_ty.m_params.m_bounds)
+ {
+ TU_MATCH_DEF(::HIR::GenericBound, (bound), (be),
+ (
+ ),
+ (TraitBound,
+ // If the bound is for Self and the outer trait
+ // - TODO: Parameters?
+ if( be.type == ::HIR::TypeRef("Self", 0xFFFF) && be.trait.m_path == e2.trait ) {
+ auto it = be.trait.m_type_bounds.find( e2.item );
+ if( it != be.trait.m_type_bounds.end() ) {
+ if( monomorphise_type_needed(it->second) ) {
+ input = monomorphise_type_with(sp, it->second, cb_placeholders_trait);
+ }
+ else {
+ input = it->second.clone();
+ }
+ input = this->expand_associated_types(sp, mv$(input));
+ return input;
+ }
+ }
+ ),
+ (TypeEquality,
+ // IF: bound's type matches the input, replace with bounded equality
+ // `<Self::IntoIter as Iterator>::Item = Self::Item`
+ 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) ) {
+ input = monomorphise_type_with(sp, be.other_type, cb_placeholders_trait);
+ }
+ else {
+ input = be.other_type.clone();
+ }
+ input = this->expand_associated_types(sp, mv$(input));
+ return input;
+ }
+ )
+ )
+ }
+ DEBUG("e2 = " << *e2.type << ", input = " << input);
+ )
+ )
+
+ // 2. Crate-level impls
+ // 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);
+
+ 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->m_ivars.type_contains_ivars(input) ) {
+ e.binding = ::HIR::TypeRef::TypePathBinding::make_Opaque({});
+ }
+
+ DEBUG("Couldn't resolve associated type for " << input);
+ ),
+ (UfcsUnknown,
+ BUG(sp, "Encountered UfcsUnknown");
+ )
+ )
+ ),
+ (Generic,
+ ),
+ (TraitObject,
+ // Recurse?
+ ),
+ (Array,
+ *e.inner = expand_associated_types(sp, mv$(*e.inner));
+ ),
+ (Slice,
+ *e.inner = expand_associated_types(sp, mv$(*e.inner));
+ ),
+ (Tuple,
+ for(auto& sub : e) {
+ sub = expand_associated_types(sp, mv$(sub));
+ }
+ ),
+ (Borrow,
+ *e.inner = expand_associated_types(sp, mv$(*e.inner));
+ ),
+ (Pointer,
+ *e.inner = expand_associated_types(sp, mv$(*e.inner));
+ ),
+ (Function,
+ // Recurse?
+ ),
+ (Closure,
+ // Recurse?
+ )
+ )
+ return input;
+}
+
+
+// -------------------------------------------------------------------------------------------------------------------
+//
+// -------------------------------------------------------------------------------------------------------------------
+bool TraitResolution::find_named_trait_in_trait(const Span& sp,
+ 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
+ ) const
+{
+ TRACE_FUNCTION_F(des << " from " << trait_path << pp);
+ if( pp.m_types.size() != trait_ptr.m_params.m_types.size() ) {
+ BUG(sp, "Incorrect number of parameters for trait");
+ }
+ for( const auto& pt : trait_ptr.m_parent_traits )
+ {
+ auto pt_mono = monomorphise_traitpath_with(sp, pt, [&](const auto& gt)->const auto& {
+ const auto& ge = gt.m_data.as_Generic();
+ if( ge.binding == 0xFFFF ) {
+ return target_type;
+ }
+ else {
+ if( ge.binding >= pp.m_types.size() )
+ BUG(sp, "find_named_trait_in_trait - Generic #" << ge.binding << " " << ge.name << " out of range");
+ return pp.m_types[ge.binding];
+ }
+ }, false);
+
+ DEBUG(pt << " => " << pt_mono);
+ if( pt.m_path.m_path == des ) {
+ callback( pt_mono.m_path.m_params, pt_mono.m_type_bounds );
+ return true;
+ }
+ }
+ return false;
+}
+bool TraitResolution::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->m_ivars.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,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 TraitResolution::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() )
+ return this->m_ivars.get_type(ty);
+ else
+ return ty;
+ },
+ [&](const auto& impl) {
+ DEBUG("[find_trait_impls_crate] Found impl" << impl.m_params.fmt_args() << " " << trait << impl.m_trait_args << " for " << impl.m_type);
+ // Compare with `params`
+ auto match = ::HIR::Compare::Equal;
+ ::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 ) {
+ // Strict equality is OK, as all types should be sane
+ // - TODO: What if there's an un-expanded associated?
+ match = ::HIR::Compare::Unequal;
+ }
+ else {
+ }
+ };
+ assert( impl.m_trait_args.m_types.size() == params.m_types.size() );
+ match &= impl.m_type.match_test_generics_fuzz(sp, type , this->m_ivars.callback_resolve_infer(), cb);
+ for(unsigned int i = 0; i < impl.m_trait_args.m_types.size(); i ++)
+ match &= impl.m_trait_args.m_types[i].match_test_generics_fuzz(sp, params.m_types[i], this->m_ivars.callback_resolve_infer(), cb);
+ if( match == ::HIR::Compare::Unequal ) {
+ DEBUG("- Failed to match parameters - " << impl.m_trait_args << " != " << params);
+ 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;
+ }
+ this->m_ivars.dump();
+ TODO(sp, "Check type bound (fuzz) " << ty2 << " = " << assoc_bound.second);
+ }
+ else {
+ if( this->m_ivars.get_type(it->second) == assoc_bound.second ) {
+ return true;
+ }
+ this->m_ivars.dump();
+ 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 << "})");
+ //if( match == ::HIR::Compare::Fuzzy ) {
+ // TODO(sp, "- Pass on fuzzy match status");
+ //}
+ return callback(args_mono, types/*, (match == ::HIR::Compare::Fuzzy)*/);
+ }
+ );
+}
+
+bool TraitResolution::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
+{
+ auto it = trait_ptr.m_values.find(name);
+ if( it != trait_ptr.m_values.end() ) {
+ if( it->second.is_Function() ) {
+ out_path = trait_path.clone();
+ return true;
+ }
+ }
+
+ // 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_method(sp, st.m_path, st_ptr, name, out_path) ) {
+ out_path.m_params = monomorphise_path_params_with(sp, mv$(out_path.m_params), [&](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];
+ }, false);
+ return true;
+ }
+ }
+ return false;
+}
+bool TraitResolution::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;
+}
+
+
+
+// -------------------------------------------------------------------------------------------------------------------
+//
+// -------------------------------------------------------------------------------------------------------------------
+const ::HIR::TypeRef* TraitResolution::autoderef(const Span& sp, const ::HIR::TypeRef& ty, ::HIR::TypeRef& tmp_type) const
+{
+ TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Borrow, e,
+ DEBUG("Deref " << ty << " into " << *e.inner);
+ return &*e.inner;
+ )
+ else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, e,
+ DEBUG("Deref " << ty << " into [" << *e.inner << "]");
+ tmp_type = ::HIR::TypeRef::new_slice( e.inner->clone() );
+ return &tmp_type;
+ )
+ else {
+ 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 ) {
+ TODO(sp, "Found a Deref impl for " << ty << ", use the output of it");
+ }
+ else {
+ return nullptr;
+ }
+ }
+}
+unsigned int TraitResolution::autoderef_find_method(const Span& sp, const HIR::t_trait_list& traits, const ::HIR::TypeRef& top_ty, const ::std::string& method_name, /* Out -> */::HIR::Path& fcn_path) const
+{
+ unsigned int deref_count = 0;
+ ::HIR::TypeRef tmp_type; // Temporary type used for handling Deref
+ const auto* current_ty = &top_ty;
+ TU_IFLET(::HIR::TypeRef::Data, this->m_ivars.get_type(top_ty).m_data, Borrow, e,
+ current_ty = &*e.inner;
+ deref_count += 1;
+ )
+
+ do {
+ const auto& ty = this->m_ivars.get_type(*current_ty);
+ if( ty.m_data.is_Infer() ) {
+ return ~0u;
+ }
+
+ if( this->find_method(sp, traits, ty, method_name, fcn_path) ) {
+ return deref_count;
+ }
+
+ // 3. Dereference and try again
+ deref_count += 1;
+ current_ty = this->autoderef(sp, ty, tmp_type);
+ } while( current_ty );
+
+ TU_IFLET(::HIR::TypeRef::Data, this->m_ivars.get_type(top_ty).m_data, Borrow, e,
+ const auto& ty = this->m_ivars.get_type(top_ty);
+
+ if( find_method(sp, traits, ty, method_name, fcn_path) ) {
+ return 0;
+ }
+ )
+
+ // Dereference failed! This is a hard error (hitting _ is checked above and returns ~0)
+ this->m_ivars.dump();
+ TODO(sp, "Error when no method could be found, but type is known - (: " << top_ty << ")." << method_name);
+}
+
+bool TraitResolution::find_method(const Span& sp, const HIR::t_trait_list& traits, const ::HIR::TypeRef& ty, const ::std::string& method_name, /* Out -> */::HIR::Path& fcn_path) const
+{
+ TRACE_FUNCTION_F("ty=" << ty << ", name=" << method_name);
+ // 1. Search generic bounds for a match
+ const ::HIR::GenericParams* v[2] = { m_item_params, m_impl_params };
+ for(auto p : v)
+ {
+ if( !p ) continue ;
+ for(const auto& b : p->m_bounds)
+ {
+ TU_IFLET(::HIR::GenericBound, b, TraitBound, e,
+ DEBUG("Bound " << e.type << " : " << e.trait.m_path);
+ // TODO: Match using _ replacement
+ if( e.type != ty )
+ continue ;
+
+ // - Bound's type matches, check if the bounded trait has the method we're searching for
+ // > TODO: Search supertraits too
+ DEBUG("- Matches " << ty);
+ ::HIR::GenericPath final_trait_path;
+ assert(e.trait.m_trait_ptr);
+ if( !this->trait_contains_method(sp, e.trait.m_path, *e.trait.m_trait_ptr, method_name, final_trait_path) )
+ continue ;
+ DEBUG("- Found trait " << final_trait_path);
+
+ // Found the method, return the UFCS path for it
+ fcn_path = ::HIR::Path( ::HIR::Path::Data::make_UfcsKnown({
+ box$( ty.clone() ),
+ mv$(final_trait_path),
+ method_name,
+ {}
+ }) );
+ return true;
+ )
+ }
+ }
+
+ TU_IFLET(::HIR::TypeRef::Data, ty.m_data, TraitObject, e,
+ // TODO: This _Should_ be set, but almost needs a pass?
+ //assert( e.m_trait.m_trait_ptr );
+ //const auto& trait = *e.m_trait.m_trait_ptr;
+ const auto& trait = this->m_crate.get_trait_by_path(sp, e.m_trait.m_path.m_path);
+ auto it = trait.m_values.find( method_name );
+ if( it != trait.m_values.end() )
+ {
+ if( it->second.is_Function() ) {
+ fcn_path = ::HIR::Path( ::HIR::Path::Data::Data_UfcsKnown({
+ box$( ty.clone() ),
+ e.m_trait.m_path.clone(),
+ method_name,
+ {}
+ }) );
+ return true;
+ }
+ }
+ )
+
+ TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Generic, e,
+ // No match, keep trying.
+ )
+ else if( ty.m_data.is_Path() && ty.m_data.as_Path().path.m_data.is_UfcsKnown() )
+ {
+ const auto& e = ty.m_data.as_Path().path.m_data.as_UfcsKnown();
+ // UFCS known - Assuming that it's reached the maximum resolvable level (i.e. a type within is generic), search for trait bounds on the type
+ const auto& trait = this->m_crate.get_trait_by_path(sp, e.trait.m_path);
+ const auto& assoc_ty = trait.m_types.at( e.item );
+ // NOTE: The bounds here have 'Self' = the type
+ for(const auto& bound : assoc_ty.m_params.m_bounds )
+ {
+ TU_IFLET(::HIR::GenericBound, bound, TraitBound, be,
+ assert(be.trait.m_trait_ptr);
+ ::HIR::GenericPath final_trait_path;
+ if( !this->trait_contains_method(sp, be.trait.m_path, *be.trait.m_trait_ptr, method_name, final_trait_path) )
+ continue ;
+ DEBUG("- Found trait " << final_trait_path);
+
+ // Found the method, return the UFCS path for it
+ fcn_path = ::HIR::Path( ::HIR::Path::Data::make_UfcsKnown({
+ box$( ty.clone() ),
+ mv$(final_trait_path),
+ method_name,
+ {}
+ }) );
+ return true;
+ )
+ }
+ }
+ else {
+ // 2. Search for inherent methods
+ for(const auto& impl : m_crate.m_type_impls)
+ {
+ if( impl.matches_type(ty) ) {
+ auto it = impl.m_methods.find( method_name );
+ if( it == impl.m_methods.end() )
+ continue ;
+ DEBUG("Matching `impl" << impl.m_params.fmt_args() << " " << impl.m_type << "`"/* << " - " << top_ty*/);
+ fcn_path = ::HIR::Path( ::HIR::Path::Data::make_UfcsInherent({
+ box$(ty.clone()),
+ method_name,
+ {}
+ }) );
+ return true;
+ }
+ }
+ // 3. Search for trait methods (using currently in-scope traits)
+ for(const auto& trait_ref : ::reverse(traits))
+ {
+ if( trait_ref.first == nullptr )
+ break;
+
+ // TODO: Search supertraits too
+ auto it = trait_ref.second->m_values.find(method_name);
+ if( it == trait_ref.second->m_values.end() )
+ continue ;
+ if( !it->second.is_Function() )
+ continue ;
+ DEBUG("Search for impl of " << *trait_ref.first);
+ // 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 << " (" /*<< m_ivars.fmt_type(*trait_ref.first)*/ << ") for " << ty << " ("<<m_ivars.fmt_type(ty)<<")");
+ fcn_path = ::HIR::Path( ::HIR::Path::Data::make_UfcsKnown({
+ box$( ty.clone() ),
+ trait_ref.first->clone(),
+ method_name,
+ {}
+ }) );
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+unsigned int TraitResolution::autoderef_find_field(const Span& sp, const ::HIR::TypeRef& top_ty, const ::std::string& field_name, /* Out -> */::HIR::TypeRef& field_type) const
+{
+ unsigned int deref_count = 0;
+ ::HIR::TypeRef tmp_type; // Temporary type used for handling Deref
+ const auto* current_ty = &top_ty;
+ TU_IFLET(::HIR::TypeRef::Data, this->m_ivars.get_type(top_ty).m_data, Borrow, e,
+ current_ty = &*e.inner;
+ deref_count += 1;
+ )
+
+ do {
+ const auto& ty = this->m_ivars.get_type(*current_ty);
+ if( ty.m_data.is_Infer() ) {
+ return ~0u;
+ }
+
+ if( this->find_field(sp, ty, field_name, field_type) ) {
+ return deref_count;
+ }
+
+ // 3. Dereference and try again
+ deref_count += 1;
+ current_ty = this->autoderef(sp, ty, tmp_type);
+ } while( current_ty );
+
+ TU_IFLET(::HIR::TypeRef::Data, this->m_ivars.get_type(top_ty).m_data, Borrow, e,
+ const auto& ty = this->m_ivars.get_type(top_ty);
+
+ if( find_field(sp, ty, field_name, field_type) ) {
+ return 0;
+ }
+ )
+
+ // Dereference failed! This is a hard error (hitting _ is checked above and returns ~0)
+ this->m_ivars.dump();
+ TODO(sp, "Error when no field could be found, but type is known - (: " << top_ty << ")." << field_name);
+}
+bool TraitResolution::find_field(const Span& sp, const ::HIR::TypeRef& ty, const ::std::string& name, /* Out -> */::HIR::TypeRef& field_ty) const
+{
+ TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Path, e,
+ TU_MATCH(::HIR::TypeRef::TypePathBinding, (e.binding), (be),
+ (Unbound,
+ // Wut?
+ TODO(sp, "Handle TypePathBinding::Unbound - " << ty);
+ ),
+ (Opaque,
+ // Ignore, no fields on an opaque
+ ),
+ (Struct,
+ // Has fields!
+ const auto& str = *be;
+ const auto& params = e.path.m_data.as_Generic().m_params;
+ auto monomorph = [&](const auto& gt)->const auto& {
+ const auto& ge = gt.m_data.as_Generic();
+ if( ge.binding == 0xFFFF )
+ TODO(sp, "Monomorphise struct field types (Self) - " << gt);
+ else if( ge.binding < 256 ) {
+ assert(ge.binding < params.m_types.size());
+ return params.m_types[ge.binding];
+ }
+ else {
+ BUG(sp, "function-level param encountered in struct field");
+ }
+ return gt;
+ };
+ TU_MATCH(::HIR::Struct::Data, (str.m_data), (se),
+ (Unit,
+ // No fields on a unit struct
+ ),
+ (Tuple,
+ for( unsigned int i = 0; i < se.size(); i ++ )
+ {
+ // TODO: Privacy
+ if( FMT(i) == name ) {
+ field_ty = monomorphise_type_with(sp, se[i].ent, monomorph);
+ return true;
+ }
+ }
+ ),
+ (Named,
+ for( const auto& fld : se )
+ {
+ // TODO: Privacy
+ if( fld.first == name ) {
+ field_ty = monomorphise_type_with(sp, fld.second.ent, monomorph);
+ return true;
+ }
+ }
+ )
+ )
+ ),
+ (Enum,
+ // No fields on enums either
+ )
+ )
+ )
+ else TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Tuple, e,
+ for( unsigned int i = 0; i < e.size(); i ++ )
+ {
+ if( FMT(i) == name ) {
+ field_ty = e[i].clone();
+ return true;
+ }
+ }
+ )
+ else {
+ }
+ return false;
+}
+
+
diff --git a/src/hir_typeck/helpers.hpp b/src/hir_typeck/helpers.hpp
index 93833f48..005186cc 100644
--- a/src/hir_typeck/helpers.hpp
+++ b/src/hir_typeck/helpers.hpp
@@ -4,6 +4,7 @@
#include <hir/type.hpp>
#include <hir/hir.hpp>
+#include <hir/expr.hpp>
// TODO/NOTE - This is identical to ::HIR::t_cb_resolve_type
typedef ::std::function<const ::HIR::TypeRef&(const ::HIR::TypeRef&)> t_cb_generic;
@@ -108,3 +109,67 @@ private:
IVar& get_pointed_ivar(unsigned int slot) const;
};
+
+// NOTE: impl is in expr_context.cpp
+class TraitResolution
+{
+ const HMTypeInferrence& m_ivars;
+
+ const ::HIR::Crate& m_crate;
+ const ::HIR::GenericParams* m_impl_params;
+ const ::HIR::GenericParams* m_item_params;
+
+public:
+ TraitResolution(const HMTypeInferrence& ivars, const ::HIR::Crate& crate, const ::HIR::GenericParams* impl_params, const ::HIR::GenericParams* item_params):
+ m_ivars(ivars),
+ m_crate(crate),
+ m_impl_params( impl_params ),
+ m_item_params( item_params )
+ {
+ }
+
+ typedef ::std::function<bool(const ::HIR::PathParams&, const ::std::map< ::std::string,::HIR::TypeRef>&)> t_cb_trait_impl;
+
+ /// Check if a trait bound applies, using the passed function to expand Generic/Infer types
+ bool check_trait_bound(const Span& sp, const ::HIR::TypeRef& type, const ::HIR::GenericPath& trait, t_cb_generic placeholder) const;
+
+ /// Expand any located associated types in the input, operating in-place and returning the result
+ ::HIR::TypeRef expand_associated_types(const Span& sp, ::HIR::TypeRef input) const;
+
+ /// 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 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::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::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 Span& sp, const ::HIR::SimplePath& trait, const ::HIR::PathParams& params, const ::HIR::TypeRef& type, t_cb_trait_impl callback) const;
+
+ /// Locate the named method by applying auto-dereferencing.
+ /// \return Number of times deref was applied (or ~0 if _ was hit)
+ unsigned int autoderef_find_method(const Span& sp, const HIR::t_trait_list& traits, const ::HIR::TypeRef& top_ty, const ::std::string& method_name, /* Out -> */::HIR::Path& fcn_path) const;
+ /// Locate the named field by applying auto-dereferencing.
+ /// \return Number of times deref was applied (or ~0 if _ was hit)
+ unsigned int autoderef_find_field(const Span& sp, const ::HIR::TypeRef& top_ty, const ::std::string& name, /* Out -> */::HIR::TypeRef& field_type) const;
+
+ /// Apply an automatic dereference
+ const ::HIR::TypeRef* autoderef(const Span& sp, const ::HIR::TypeRef& ty, ::HIR::TypeRef& tmp_type) const;
+
+private:
+ bool find_method(const Span& sp, const HIR::t_trait_list& traits, const ::HIR::TypeRef& ty, const ::std::string& method_name, /* Out -> */::HIR::Path& fcn_path) const;
+ bool find_field(const Span& sp, const ::HIR::TypeRef& ty, const ::std::string& name, /* Out -> */::HIR::TypeRef& field_type) 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;
+};
+