summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/hir_typeck/static.cpp377
-rw-r--r--src/hir_typeck/static.hpp1
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: