summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/hir_typeck/expr_cs.cpp59
1 files changed, 45 insertions, 14 deletions
diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp
index 1e0ef177..975c6b47 100644
--- a/src/hir_typeck/expr_cs.cpp
+++ b/src/hir_typeck/expr_cs.cpp
@@ -4886,16 +4886,13 @@ namespace {
return ;
}
- //enum class List {
- // CoerceTo,
- // CoerceFrom,
- // UnsizeTo,
- // UnsizeFrom,
- //};
+ enum class DedupKeep {
+ Both,
+ Left,
+ Right,
+ };
struct H {
- // De-duplicate list (taking into account other ivars)
- // - TODO: Use the direction and do a fuzzy equality based on coercion possibility
- static void dedup_type_list(const Context& context, ::std::vector< ::HIR::TypeRef>& list) {
+ static void dedup_type_list_with(::std::vector< ::HIR::TypeRef>& list, ::std::function<DedupKeep(const ::HIR::TypeRef& l, const ::HIR::TypeRef& r)> cmp) {
if( list.size() <= 1 )
return ;
@@ -4903,8 +4900,16 @@ namespace {
{
bool found = false;
for( auto it2 = list.begin(); it2 != it; ++ it2 ) {
- //if( context.m_ivars.types_equal( **it, **it2 ) ) {
- if( H::equal_to(context, *it, *it2) ) {
+ auto action = cmp(*it, *it2);
+ if( action != DedupKeep::Both )
+ {
+ if( action == DedupKeep::Right ) {
+ //DEBUG("Keep " << *it << ", toss " << *it2);
+ }
+ else {
+ ::std::swap(*it2, *it);
+ //DEBUG("Keep " << *it << ", toss " << *it2 << " (swapped)");
+ }
found = true;
break;
}
@@ -4917,6 +4922,11 @@ namespace {
}
}
}
+ // De-duplicate list (taking into account other ivars)
+ // - TODO: Use the direction and do a fuzzy equality based on coercion possibility
+ static void dedup_type_list(const Context& context, ::std::vector< ::HIR::TypeRef>& list) {
+ dedup_type_list_with(list, [&context](const auto& l, const auto& r){ return H::equal_to(context, l, r) ? DedupKeep::Left : DedupKeep::Both; });
+ }
// Types are equal from the view of being coercion targets
// - Inequality here means that the targets could coexist (e.g. &[u8; N] and &[u8])
@@ -5077,10 +5087,9 @@ namespace {
{
TRACE_FUNCTION_F(i);
- // TODO: Some cases lead to two possibilities that compare different (due to inferrence) but are actually the same.
- // - The above dedup should probably be aware of the way the types are used (for coercions).
- // TODO: Dedup based on context.
+ // TODO: Dedup based on context?
+ // - The dedup should probably be aware of the way the types are used (for coercions).
H::dedup_type_list(context, ivar_ent.types_coerce_to);
H::dedup_type_list(context, ivar_ent.types_unsize_to);
H::dedup_type_list(context, ivar_ent.types_coerce_from);
@@ -5105,6 +5114,28 @@ namespace {
DEBUG("-- " << ty_l << " FROM=Coerce:[" << ivar_ent.types_coerce_from << "] / Unsize:[" << ivar_ent.types_unsize_from << "],"
<< " TO=Coerce:[" << ivar_ent.types_coerce_to << "] / Unsize:[" << ivar_ent.types_unsize_to << "]");
+ // TODO: Find an entry in the `types_unsize_from` list that all other entries can unsize to
+ H::dedup_type_list_with(ivar_ent.types_unsize_from, [&](const auto& l, const auto& r) {
+ // &T and T
+ TU_IFLET( ::HIR::TypeRef::Data, l.m_data, Borrow, le,
+ TU_IFLET( ::HIR::TypeRef::Data, r.m_data, Borrow, re,
+ )
+ else {
+ // if *le.inner == r, return DedupKeep::Right
+ if( context.m_ivars.types_equal(*le.inner, r) )
+ return DedupKeep::Right;
+ }
+ )
+ else {
+ TU_IFLET( ::HIR::TypeRef::Data, r.m_data, Borrow, re,
+ // if *re.inner == l, return DedupKeep::Left
+ if( context.m_ivars.types_equal(*re.inner, l) )
+ return DedupKeep::Left;
+ )
+ }
+ return DedupKeep::Both;
+ });
+
// HACK: Merge into a single list.
::std::vector< ::HIR::TypeRef> types_from_o;
const auto* types_from_p = &types_from_o;