@@ -6,10 +6,10 @@ use chalk_ir::interner::{HasInterner, Interner};
6
6
use chalk_ir:: visit:: Visit ;
7
7
use chalk_ir:: zip:: Zip ;
8
8
use chalk_ir:: {
9
- Binders , Canonical , ConstrainedSubst , Constraint , Constraints , DomainGoal , Environment , EqGoal ,
10
- Fallible , GenericArg , Goal , GoalData , InEnvironment , NoSolution , ProgramClauseImplication ,
11
- QuantifierKind , Substitution , SubtypeGoal , TyKind , TyVariableKind , UCanonical ,
12
- UnificationDatabase , UniverseMap , Variance ,
9
+ Binders , BoundVar , Canonical , ConstrainedSubst , Constraint , Constraints , DomainGoal ,
10
+ Environment , EqGoal , Fallible , GenericArg , GenericArgData , Goal , GoalData , InEnvironment ,
11
+ NoSolution , ProgramClauseImplication , QuantifierKind , Substitution , SubtypeGoal , TyKind ,
12
+ TyVariableKind , UCanonical , UnificationDatabase , UniverseMap , Variance ,
13
13
} ;
14
14
use chalk_solve:: debug_span;
15
15
use chalk_solve:: infer:: { InferenceTable , ParameterEnaVariableExt } ;
@@ -466,17 +466,19 @@ impl<'s, I: Interner, Solver: SolveDatabase<I>> Fulfill<'s, I, Solver> {
466
466
} = self . prove ( wc. clone ( ) , minimums) ?;
467
467
468
468
if let Some ( constrained_subst) = solution. definite_subst ( self . interner ( ) ) {
469
- // If the substitution is empty , we won't actually make any progress by applying it!
469
+ // If the substitution is trivial , we won't actually make any progress by applying it!
470
470
// So we need to check this to prevent endless loops.
471
- // (An ambiguous solution with empty substitution
472
- // can probably not happen in valid code, but it can
473
- // happen e.g. when there are overlapping impls.)
474
- if !constrained_subst. value . subst . is_empty ( self . interner ( ) )
475
- || !constrained_subst
476
- . value
477
- . constraints
478
- . is_empty ( self . interner ( ) )
479
- {
471
+ let nontrivial_subst = !is_trivial_canonical_subst (
472
+ self . interner ( ) ,
473
+ & constrained_subst. value . subst ,
474
+ ) ;
475
+
476
+ let has_constraints = !constrained_subst
477
+ . value
478
+ . constraints
479
+ . is_empty ( self . interner ( ) ) ;
480
+
481
+ if nontrivial_subst || has_constraints {
480
482
self . apply_solution ( free_vars, universes, constrained_subst) ;
481
483
progress = true ;
482
484
}
@@ -608,3 +610,28 @@ impl<'s, I: Interner, Solver: SolveDatabase<I>> Fulfill<'s, I, Solver> {
608
610
self . solver . interner ( )
609
611
}
610
612
}
613
+
614
+ fn is_trivial_canonical_subst < I : Interner > ( interner : I , subst : & Substitution < I > ) -> bool {
615
+ // A subst is trivial if..
616
+ subst. iter ( interner) . enumerate ( ) . all ( |( index, parameter) | {
617
+ let is_trivial = |b : Option < BoundVar > | match b {
618
+ None => false ,
619
+ Some ( bound_var) => {
620
+ if let Some ( index1) = bound_var. index_if_innermost ( ) {
621
+ index == index1
622
+ } else {
623
+ false
624
+ }
625
+ }
626
+ } ;
627
+
628
+ match parameter. data ( interner) {
629
+ // All types and consts are mapped to distinct variables. Since this
630
+ // has been canonicalized, those will also be the first N
631
+ // variables.
632
+ GenericArgData :: Ty ( t) => is_trivial ( t. bound_var ( interner) ) ,
633
+ GenericArgData :: Const ( t) => is_trivial ( t. bound_var ( interner) ) ,
634
+ GenericArgData :: Lifetime ( t) => is_trivial ( t. bound_var ( interner) ) ,
635
+ }
636
+ } )
637
+ }
0 commit comments