diff options
-rw-r--r-- | src/hir_typeck/static.cpp | 377 | ||||
-rw-r--r-- | src/hir_typeck/static.hpp | 1 |
2 files changed, 193 insertions, 185 deletions
diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp index 786531d8..7683c2c1 100644 --- a/src/hir_typeck/static.cpp +++ b/src/hir_typeck/static.cpp @@ -410,191 +410,8 @@ void StaticTraitResolve::expand_associated_types(const Span& sp, ::HIR::TypeRef& // - Only try resolving if the binding isn't known if( !e.binding.is_Unbound() ) return ; - - this->expand_associated_types(sp, *e2.type); - for(auto& arg : e2.trait.m_params.m_types) - this->expand_associated_types(sp, arg); - - DEBUG("Locating associated type for " << e.path); - - // - 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, - //if( te.node->m_obj_path == ::HIR::GenericPath() ) - //{ - 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" ) { - input = te.m_rettype->clone(); - return ; - } - 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); - } - //} - //else - //{ - // // TODO: Locate impl _without_ binding params too hard? - //} - ) - - // 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& params, 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 ) { - input.m_data.as_Path().binding = ::HIR::TypeRef::TypePathBinding::make_Opaque({}); - DEBUG("Assuming that " << input << " is an opaque name"); - - this->replace_equalities(input); - } - this->expand_associated_types(sp, input); - return; - } - - // 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); - - // 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_trait_bounds) - { - // If the bound is for Self and the outer trait - // - TODO: Parameters? - if( bound.m_path == e2.trait ) { - auto it = bound.m_type_bounds.find( e2.item ); - if( it != bound.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(); - } - this->expand_associated_types(sp, input); - return ; - } - } - } - 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_impl(sp, trait_path.m_path, trait_path.m_params, *e2.type, [&](const auto& impl) { - DEBUG("[expand_associated_types] Found " << impl); - - auto nt = impl.get_type( e2.item.c_str() ); - DEBUG("Converted UfcsKnown - " << e.path << " = " << nt); - input = mv$(nt); - return true; - }); - if( rv ) { - this->expand_associated_types(sp, input); - return; - } - - // TODO: If the type is a generic or an opaque associated, we can't know. - // - If the trait contains any of the above, it's unknowable - // - Otherwise, it's an error - e.binding = ::HIR::TypeRef::TypePathBinding::make_Opaque({}); - this->replace_equalities(input); - DEBUG("Couldn't resolve associated type for " << input << " (and won't ever be able to, assuming opaque)"); + this->expand_associated_types__UfcsKnown(sp, input); + return; ), (UfcsUnknown, BUG(sp, "Encountered UfcsUnknown"); @@ -631,6 +448,196 @@ void StaticTraitResolve::expand_associated_types(const Span& sp, ::HIR::TypeRef& ) ) } +void StaticTraitResolve::expand_associated_types__UfcsKnown(const Span& sp, ::HIR::TypeRef& input) const +{ + auto& e = input.m_data.as_Path(); + auto& e2 = e.path.m_data.as_UfcsKnown(); + + this->expand_associated_types(sp, *e2.type); + for(auto& arg : e2.trait.m_params.m_types) + this->expand_associated_types(sp, arg); + + DEBUG("Locating associated type for " << e.path); + + // - 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, + //if( te.node->m_obj_path == ::HIR::GenericPath() ) + //{ + 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" ) { + input = te.m_rettype->clone(); + return ; + } + 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); + } + //} + //else + //{ + // // TODO: Locate impl _without_ binding params too hard? + //} + ) + + // 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& params, 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 ) { + input.m_data.as_Path().binding = ::HIR::TypeRef::TypePathBinding::make_Opaque({}); + DEBUG("Assuming that " << input << " is an opaque name"); + + this->replace_equalities(input); + } + this->expand_associated_types(sp, input); + return; + } + + // 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); + + // 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_trait_bounds) + { + // If the bound is for Self and the outer trait + // - TODO: Parameters? + if( bound.m_path == e2.trait ) { + auto it = bound.m_type_bounds.find( e2.item ); + if( it != bound.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(); + } + this->expand_associated_types(sp, input); + return ; + } + } + } + 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_impl(sp, trait_path.m_path, trait_path.m_params, *e2.type, [&](const auto& impl) { + DEBUG("[expand_associated_types] Found " << impl); + + auto nt = impl.get_type( e2.item.c_str() ); + DEBUG("Converted UfcsKnown - " << e.path << " = " << nt); + input = mv$(nt); + return true; + }); + if( rv ) { + this->expand_associated_types(sp, input); + return; + } + + // TODO: If the type is a generic or an opaque associated, we can't know. + // - If the trait contains any of the above, it's unknowable + // - Otherwise, it's an error + e.binding = ::HIR::TypeRef::TypePathBinding::make_Opaque({}); + this->replace_equalities(input); + DEBUG("Couldn't resolve associated type for " << input << " (and won't ever be able to, assuming opaque)"); +} void StaticTraitResolve::replace_equalities(::HIR::TypeRef& input) const { diff --git a/src/hir_typeck/static.hpp b/src/hir_typeck/static.hpp index 5f24fc11..ecbdc6d7 100644 --- a/src/hir_typeck/static.hpp +++ b/src/hir_typeck/static.hpp @@ -117,6 +117,7 @@ public: void expand_associated_types(const Span& sp, ::HIR::TypeRef& input) const; private: + void expand_associated_types__UfcsKnown(const Span& sp, ::HIR::TypeRef& input) const; void replace_equalities(::HIR::TypeRef& input) const; public: |