summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/hir/type.hpp2
-rw-r--r--src/hir_typeck/helpers.cpp64
2 files changed, 55 insertions, 11 deletions
diff --git a/src/hir/type.hpp b/src/hir/type.hpp
index b8af896f..940ebc04 100644
--- a/src/hir/type.hpp
+++ b/src/hir/type.hpp
@@ -226,6 +226,8 @@ public:
void match_generics(const Span& sp, const ::HIR::TypeRef& x, t_cb_resolve_type resolve_placeholder, ::std::function<void(unsigned int, const ::HIR::TypeRef&)> callback) const;
bool match_test_generics(const Span& sp, const ::HIR::TypeRef& x, t_cb_resolve_type resolve_placeholder, ::std::function<void(unsigned int, const ::HIR::TypeRef&)> callback) const;
+
+ // Compares this type with another, calling the first callback to resolve placeholders in the other type, and the second callback for generics in this type
::HIR::Compare match_test_generics_fuzz(const Span& sp, const ::HIR::TypeRef& x_in, t_cb_resolve_type resolve_placeholder, t_cb_match_generics callback) const;
// Compares this type with another, using `resolve_placeholder` to get replacements for generics/infers in `x`
diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp
index 2ba08343..8f877b25 100644
--- a/src/hir_typeck/helpers.cpp
+++ b/src/hir_typeck/helpers.cpp
@@ -1455,12 +1455,17 @@ bool TraitResolution::has_associated_type(const ::HIR::TypeRef& input) const
return input;
}
- // TODO: If there are no ivars in this path, set its binding to Opaque
+ // If there are no ivars in this path, set its binding to Opaque
if( !this->m_ivars.type_contains_ivars(input) ) {
+ // 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({});
+ DEBUG("Couldn't resolve associated type for " << input << " (and won't ever be able to)");
+ }
+ else {
+ DEBUG("Couldn't resolve associated type for " << input << " (will try again later)");
}
-
- DEBUG("Couldn't resolve associated type for " << input);
),
(UfcsUnknown,
BUG(sp, "Encountered UfcsUnknown");
@@ -1705,16 +1710,48 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
DEBUG("- Failed to match parameters - " << impl.m_trait_args << "+" << impl.m_type << " != " << params << "+" << type);
return false;
}
+
+ // TODO: Some impl blocks have type params used as part of type bounds.
+ // - A rough idea is to have monomorph return a third class of generic for params that are not yet bound.
+ // - compare_with_placeholders gets called on both ivars and generics, so that can be used to replace it once known.
+ ::std::vector< ::HIR::TypeRef> placeholders;
for(unsigned int i = 0; i < impl_params.size(); i ++ ) {
if( !impl_params[i] ) {
- BUG(sp, "Param " << i << " for impl" << impl.m_params.fmt_args() << " " << trait << impl.m_trait_args << " for " << impl.m_type << " wasn't constrained");
+ if( placeholders.size() == 0 )
+ placeholders.resize(impl_params.size());
+ placeholders[i] = ::HIR::TypeRef("impl_?", i);
}
}
-
+ #if 0
+ auto cb_infer = [&](const auto& ty) {
+ if( ty.m_data.is_Infer() )
+ return this->m_ivars.get_type(ty);
+ else if( ty.m_data.is_Generic() && ty.m_data.as_Generic().binding >> 8 == 2 ) // Generic group 2 = Placeholders
+ unsigned int i = ty.m_data.as_Generic().binding % 256;
+ TODO(sp, "Obtain placeholder " << i);
+ else
+ return ty;
+ };
+ auto cb_match = [&](unsigned int idx, const auto& ty) {
+ if( idx >> 8 == 2 ) {
+ auto i = idx % 256;
+ TODO(sp, "Compare/bind placeholder " << i);
+ }
+ else {
+ if( ty.m_data.is_Generic() && ty.m_data.as_Generic().binding == idx )
+ return ::HIR::Compare::Equal;
+ else
+ return ::HIR::Compare::Unequal;
+ }
+ };
+ #endif
auto monomorph = [&](const auto& gt)->const auto& {
const auto& ge = gt.m_data.as_Generic();
assert( ge.binding < impl_params.size() );
- assert(impl_params[ge.binding]);
+ if( !impl_params[ge.binding] ) {
+ BUG(sp, "Param " << ge.binding << " for `impl" << impl.m_params.fmt_args() << " " << trait << impl.m_trait_args << " for " << impl.m_type << "` wasn't constrained");
+ return placeholders[ge.binding];
+ }
return *impl_params[ge.binding];
};
auto ty_mono = monomorphise_type_with(sp, impl.m_type, monomorph, false);
@@ -1733,11 +1770,12 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
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);
+ const auto& real_trait_path = real_trait.m_path;
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&, const auto& a, const auto& t) {
+ DEBUG("- " << real_type << " : " << real_trait_path);
+ auto rv = this->find_trait_impls(sp, real_trait_path.m_path, real_trait_path.m_params, real_type, [&](const auto&, const auto& a, const auto& t) {
for(const auto& assoc_bound : real_trait.m_type_bounds) {
::HIR::TypeRef tmp;
const ::HIR::TypeRef* ty_p;
@@ -1747,7 +1785,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
{
// This bound isn't from this particular trait, go the slow way of using expand_associated_types
tmp = this->expand_associated_types(sp, ::HIR::TypeRef(
- ::HIR::Path(::HIR::Path::Data::Data_UfcsKnown { box$(real_type.clone()), real_trait.m_path.clone(), assoc_bound.first, {} }))
+ ::HIR::Path(::HIR::Path::Data::Data_UfcsKnown { box$(real_type.clone()), real_trait_path.clone(), assoc_bound.first, {} }))
);
ty_p = &tmp;
}
@@ -1755,23 +1793,27 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
ty_p = &this->m_ivars.get_type(it->second);
}
const auto& ty = *ty_p;
- auto cmp = ty.compare_with_placeholders(sp, assoc_bound.second, this->m_ivars.callback_resolve_infer());
+ DEBUG(" - Compare " << ty << " and " << assoc_bound.second << ", matching generics");
+ auto cmp = assoc_bound.second .compare_with_placeholders(sp, ty, this->m_ivars.callback_resolve_infer());
+ //auto cmp = assoc_bound.second .match_test_generics_fuzz(sp, ty, cb_infer, cb_match);
switch(cmp)
{
case ::HIR::Compare::Equal:
continue;
case ::HIR::Compare::Unequal:
+ DEBUG("Assoc failure - " << ty << " != " << assoc_bound.second);
return false;
case ::HIR::Compare::Fuzzy:
// TODO: When a fuzzy match is encountered on a conditional bound, returning `false` can lead to an false negative (and a compile error)
// BUT, returning `true` could lead to it being selected. (Is this a problem, should a later validation pass check?)
- DEBUG("[find_trait_impls_crate] Fuzzy match between " << ty << " and " << assoc_bound.second);
+ DEBUG("[find_trait_impls_crate] Fuzzy match assoc bound between " << ty << " and " << assoc_bound.second);
continue ;
}
}
return true;
});
if( !rv ) {
+ DEBUG("- Bound " << real_type << " : " << real_trait_path << " failed");
return false;
}
),