summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@ucc.asn.au>2018-02-25 10:52:11 +0800
committerJohn Hodge <tpg@ucc.asn.au>2018-02-25 11:12:42 +0800
commit8e002015416954fa5e9444c9d81ec7f4b291562f (patch)
treee332b1efa4618ac06aa306ed3e4d4f33235a1507
parentcec5b32e9918c97b0b044ff30b86892d974c82f4 (diff)
downloadmrust-8e002015416954fa5e9444c9d81ec7f4b291562f.tar.gz
HIR Typecheck - Fix case where inferrence stalls when there's a `T = <T>::Assoc bound` and unsizing, should fix #62
-rw-r--r--samples/test/issue-mrustc-62.rs17
-rw-r--r--src/hir_typeck/expr_cs.cpp77
2 files changed, 77 insertions, 17 deletions
diff --git a/samples/test/issue-mrustc-62.rs b/samples/test/issue-mrustc-62.rs
new file mode 100644
index 00000000..c319ad83
--- /dev/null
+++ b/samples/test/issue-mrustc-62.rs
@@ -0,0 +1,17 @@
+
+struct Struct;
+
+trait Trait {
+ type Assoc;
+}
+
+impl Trait for Struct {
+ type Assoc = Struct;
+}
+
+fn f<S>(_: &S) where S: Trait<Assoc = S> {}
+
+fn main() {
+ f(&Struct);
+}
+
diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp
index ed2808e4..4f698c15 100644
--- a/src/hir_typeck/expr_cs.cpp
+++ b/src/hir_typeck/expr_cs.cpp
@@ -5445,13 +5445,14 @@ namespace {
}
}
- bool check_ivar_poss(Context& context, unsigned int i, Context::IVarPossible& ivar_ent)
+ bool check_ivar_poss(Context& context, unsigned int i, Context::IVarPossible& ivar_ent, bool honour_disable=true)
{
static Span _span;
const auto& sp = _span;
if( ! ivar_ent.has_rules() ) {
// No rules, don't do anything (and don't print)
+ DEBUG(i << ": No rules");
return false;
}
@@ -5758,7 +5759,7 @@ namespace {
return false;
}
- if( ivar_ent.force_no_to || ivar_ent.force_no_from )
+ if( honour_disable && (ivar_ent.force_no_to || ivar_ent.force_no_from) )
{
DEBUG("- IVar " << ty_l << " is forced unknown");
return false;
@@ -5787,6 +5788,7 @@ namespace {
&& ivar_ent.types_unsize_from.size() == 0 && ivar_ent.types_unsize_to.size() == 0
)
{
+ DEBUG("-- No known options for " << ty_l);
return false;
}
DEBUG("-- " << ty_l << " FROM=Coerce:{" << ivar_ent.types_coerce_from << "} / Unsize:{" << ivar_ent.types_unsize_from << "},"
@@ -6029,7 +6031,7 @@ namespace {
if( e->index < context.possible_ivar_vals.size() )
{
const auto& p = context.possible_ivar_vals[e->index];
- if(p.force_no_to || p.force_no_from)
+ if( honour_disable && (p.force_no_to || p.force_no_from) )
{
DEBUG("- IVar " << ty_l << " ?= " << ty_r << " (single " << list_name << ", rhs disabled)");
return false;
@@ -6273,19 +6275,7 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
//assert( !context.m_ivars.peek_changed() );
}
}
- for(auto& ivar_ent : context.possible_ivar_vals)
- {
- ivar_ent.reset();
- }
- }
- else
- {
- // Clear ivar possibilities for next pass
- for(auto& ivar_ent : context.possible_ivar_vals)
- {
- ivar_ent.reset();
- }
- }
+ } // `if peek_changed` (ivar possibilities)
if( !context.m_ivars.peek_changed() )
{
@@ -6317,7 +6307,54 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
}
}
#endif
- }
+ } // `if peek_changed` (node revisits)
+
+ // If nothing has changed, run check_ivar_poss again but ignoring the 'disable' flag
+ if( !context.m_ivars.peek_changed() )
+ {
+ // Check the possible equations
+ DEBUG("--- IVar possibilities (fallback)");
+ // NOTE: Ordering is a hack for libgit2
+ for(unsigned int i = context.possible_ivar_vals.size(); i --; )
+ {
+ if( check_ivar_poss(context, i, context.possible_ivar_vals[i], /*honour_disable=*/false) ) {
+ static Span sp;
+ assert( context.possible_ivar_vals[i].has_rules() );
+ // Disable all metioned ivars in the possibilities
+ for(const auto& ty : context.possible_ivar_vals[i].types_coerce_to)
+ context.equate_types_from_shadow(sp,ty);
+ for(const auto& ty : context.possible_ivar_vals[i].types_unsize_to)
+ context.equate_types_from_shadow(sp,ty);
+ for(const auto& ty : context.possible_ivar_vals[i].types_coerce_from)
+ context.equate_types_to_shadow(sp,ty);
+ for(const auto& ty : context.possible_ivar_vals[i].types_unsize_from)
+ context.equate_types_to_shadow(sp,ty);
+
+ // Also disable inferrence (for this pass) for all ivars in affected bounds
+ for(const auto& la : context.link_assoc)
+ {
+ bool found = false;
+ auto cb = [&](const auto& t) { return TU_TEST1(t.m_data, Infer, .index == i); };
+ if( la.left_ty != ::HIR::TypeRef() )
+ found |= visit_ty_with( la.left_ty, cb );
+ found |= visit_ty_with( la.impl_ty, cb );
+ for(const auto& t : la.params.m_types)
+ found |= visit_ty_with( t, cb );
+ if( found )
+ {
+ if(la.left_ty != ::HIR::TypeRef())
+ context.equate_types_shadow(sp, la.left_ty, false);
+ context.equate_types_shadow(sp, la.impl_ty, false);
+ for(const auto& t : la.params.m_types)
+ context.equate_types_shadow(sp, t, false);
+ }
+ }
+ }
+ else {
+ //assert( !context.m_ivars.peek_changed() );
+ }
+ }
+ } // `if peek_changed` (ivar possibilities #2)
// Finally. If nothing changed, apply ivar defaults
if( !context.m_ivars.peek_changed() )
@@ -6328,6 +6365,12 @@ void Typecheck_Code_CS(const typeck::ModuleState& ms, t_args& args, const ::HIR:
}
}
+ // Clear ivar possibilities for next pass
+ for(auto& ivar_ent : context.possible_ivar_vals)
+ {
+ ivar_ent.reset();
+ }
+
count ++;
context.m_resolve.compact_ivars(context.m_ivars);
}