diff options
author | John Hodge <tpg@mutabah.net> | 2016-07-03 19:56:24 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2016-07-03 19:56:24 +0800 |
commit | 909257298c23f449491c57d8f4b91bfc6a7b077b (patch) | |
tree | 2acddca3f3316cd60392ac7d9fe96c02b68d2016 /src | |
parent | 08290af3aa179c24e34b6d516265c1b789514893 (diff) | |
download | mrust-909257298c23f449491c57d8f4b91bfc6a7b077b.tar.gz |
HIR Typecheck - Move TraitResolve to helpers.cpp
Diffstat (limited to 'src')
-rw-r--r-- | src/hir_typeck/expr_context.cpp | 903 | ||||
-rw-r--r-- | src/hir_typeck/expr_cs.cpp | 81 | ||||
-rw-r--r-- | src/hir_typeck/expr_simple.hpp | 62 | ||||
-rw-r--r-- | src/hir_typeck/helpers.cpp | 908 | ||||
-rw-r--r-- | src/hir_typeck/helpers.hpp | 65 |
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; +}; + |