summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/hir_typeck/expr_cs.cpp75
-rw-r--r--src/hir_typeck/helpers.cpp51
2 files changed, 116 insertions, 10 deletions
diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp
index af42bc07..6ced24c8 100644
--- a/src/hir_typeck/expr_cs.cpp
+++ b/src/hir_typeck/expr_cs.cpp
@@ -3413,15 +3413,16 @@ namespace {
::HIR::PathParams pp;
pp.m_types.push_back( ty_dst.clone() );
- // PROBLEM: In the desugaring of `box`, it's required that the container type propagate backwards through the coercion point
- // - However, there's still a coercion point that needs to apply to the contained type.
- // - `let foo: Box<[i32]> = box [1, 2, 3];`
- // - Special-casing `Box` here could work (assuming that Box can only coerce to Box, and applying unsizing coercion rules to the inner)
+ // PROBLEM: This can false-negative leading to the types being falsely equated.
- //bool fuzzy_match = false;
+ bool fuzzy_match = false;
bool found = context.m_resolve.find_trait_impls(sp, lang_CoerceUnsized, pp, ty_src, [&](auto impl, auto cmp) {
- // TODO: Allow fuzzy match if it's the only matching possibility
DEBUG("[check_coerce] cmp=" << cmp << ", impl=" << impl);
+ // TODO: Allow fuzzy match if it's the only matching possibility?
+ // - Recorded for now to know if a later pass is a good idea
+ if( cmp == ::HIR::Compare::Fuzzy ) {
+ fuzzy_match = true;
+ }
return cmp == ::HIR::Compare::Equal;
});
if( found )
@@ -3432,12 +3433,74 @@ namespace {
node_ptr = NEWNODE( ty_dst.clone(), span, _Unsize, mv$(node_ptr), ty_dst.clone() );
return true;
}
+ if( fuzzy_match )
+ {
+ const auto& span = sp;
+ // TODO: Apply ivar possibilities between the parameters in `ty_src` and `ty_dst`
+ // - Ideally, this equivalence would be done using the parameter known to be the pointer target
+ if( ty_dst.m_data.is_Path() && ty_src.m_data.is_Path() )
+ {
+ const auto& dp = ty_dst.m_data.as_Path().path;
+ const auto& sp = ty_src.m_data.as_Path().path;
+ if( dp.m_data.is_Generic() && sp.m_data.is_Generic() )
+ {
+ const auto& dpe = dp.m_data.as_Generic();
+ const auto& spe = sp.m_data.as_Generic();
+ if( dpe.m_path == spe.m_path && dpe.m_params.m_types.size() > 0 )
+ {
+ ASSERT_BUG(node_ptr->span(), dpe.m_params.m_types.size() == spe.m_params.m_types.size(),
+ "Mismatch in type param count - `" << dpe.m_params << "` and `" << spe.m_params << "`");
+ for(unsigned int i = 0; i < dpe.m_params.m_types.size(); i ++)
+ {
+ const auto& dt2 = context.get_type(dpe.m_params.m_types[i]);
+ const auto& st2 = context.get_type(spe.m_params.m_types[i]);
+
+ // Ideally, this would share code with other sections
+ TU_IFLET( ::HIR::TypeRef::Data, st2.m_data, Infer, se,
+ // TODO: Update for InferClass::Diverge ?
+ if( se.ty_class != ::HIR::InferClass::None ) {
+ context.equate_types(span, dt2, st2);
+ }
+ else {
+ TU_IFLET(::HIR::TypeRef::Data, dt2.m_data, Infer, de,
+ context.possible_equate_type_to(se.index, dt2);
+ context.possible_equate_type_from(de.index, st2);
+ )
+ else {
+ context.possible_equate_type_to(se.index, dt2);
+ }
+ }
+ )
+ else TU_IFLET(::HIR::TypeRef::Data, dt2.m_data, Infer, de,
+ // TODO: Update for InferClass::Diverge ?
+ if( de.ty_class != ::HIR::InferClass::None ) {
+ context.equate_types(span, dt2, st2);
+ }
+ else {
+ context.possible_equate_type_from(de.index, st2);
+ }
+ )
+ else {
+ // No equivalence added
+ }
+ }
+ }
+ }
+ }
+ #if 1
+ DEBUG("- CoerceUnsize possible, trying later");
+ return false;
+ #else
+ DEBUG("- CoerceUnsize possible?");
+ #endif
+ }
}
// 1. Check that the source type can coerce
TU_MATCH( ::HIR::TypeRef::Data, (ty_src.m_data), (e),
(Infer,
// If this ivar is of a primitive, equate (as primitives never coerce)
+ // TODO: InferClass::Diverge
if( e.ty_class != ::HIR::InferClass::None ) {
context.equate_types(sp, ty_dst, ty_src);
return true;
diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp
index b35d6438..bc020ef5 100644
--- a/src/hir_typeck/helpers.cpp
+++ b/src/hir_typeck/helpers.cpp
@@ -964,6 +964,27 @@ bool TraitResolution::find_trait_impls(const Span& sp,
return false;
}
}
+
+ // Magical CoerceUnsized impls for various types
+ if( trait == this->m_crate.get_lang_item_path(sp, "coerce_unsized") ) {
+ const auto& dst_ty = params.m_types.at(0);
+ // - `*mut T => *const T`
+ TU_IFLET( ::HIR::TypeRef::Data, type.m_data, Pointer, e,
+ TU_IFLET( ::HIR::TypeRef::Data, dst_ty.m_data, Pointer, de,
+ if( de.type < e.type ) {
+ auto cmp = e.inner->compare_with_placeholders(sp, *de.inner, this->m_ivars.callback_resolve_infer());
+ if( cmp != ::HIR::Compare::Unequal )
+ {
+ ::HIR::PathParams pp;
+ pp.m_types.push_back( dst_ty.clone() );
+ if( callback( ImplRef(type.clone(), mv$(pp), {}), cmp ) ) {
+ return true;
+ }
+ }
+ }
+ )
+ )
+ }
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");
@@ -1943,7 +1964,7 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
(TypeLifetime,
),
(TraitBound,
- DEBUG("Check bound " << be.type << " : " << be.trait);
+ DEBUG("[find_trait_impls_crate] 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);
real_type = this->expand_associated_types(sp, mv$(real_type));
@@ -1954,8 +1975,10 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
ab.second = this->expand_associated_types(sp, mv$(ab.second));
}
const auto& real_trait_path = real_trait.m_path;
- DEBUG("- " << real_type << " : " << real_trait);
+ DEBUG("[find_trait_impls_crate] - bound mono " << real_type << " : " << real_trait);
+ bool found_fuzzy_match = false;
auto rv = this->find_trait_impls(sp, real_trait_path.m_path, real_trait_path.m_params, real_type, [&](auto impl, auto impl_cmp) {
+ auto cmp = impl_cmp;
for(const auto& assoc_bound : real_trait.m_type_bounds) {
::HIR::TypeRef tmp;
const ::HIR::TypeRef* ty_p;
@@ -1986,12 +2009,32 @@ bool TraitResolution::find_trait_impls_crate(const Span& sp,
// 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 assoc bound between " << ty << " and " << assoc_bound.second);
+ cmp = ::HIR::Compare::Fuzzy;
continue ;
}
}
- return true;
+ DEBUG("impl_cmp = " << impl_cmp << ", cmp = " << cmp);
+ if( cmp == ::HIR::Compare::Fuzzy ) {
+ found_fuzzy_match = true;
+ }
+ // If the match isn't a concrete equal, return false (to keep searching)
+ return (cmp == ::HIR::Compare::Equal);
});
- if( !rv ) {
+ if( rv ) {
+ DEBUG("- Bound " << real_type << " : " << real_trait_path << " matched");
+ }
+ else if( found_fuzzy_match ) {
+ DEBUG("- Bound " << real_type << " : " << real_trait_path << " fuzzed");
+ match = ::HIR::Compare::Fuzzy;
+ }
+ #if 1
+ // TODO: This causes typeck errors in libcore
+ else if( real_type.m_data.is_Infer() && real_type.m_data.as_Infer().ty_class == ::HIR::InferClass::None ) {
+ DEBUG("- Bound " << real_type << " : " << real_trait_path << " full infer type - make result fuzzy");
+ match = ::HIR::Compare::Fuzzy;
+ }
+ #endif
+ else {
DEBUG("- Bound " << real_type << " : " << real_trait_path << " failed");
return false;
}