@@ -93,34 +93,32 @@ pub struct EvalCtxt<'a, 'tcx> {
93
93
94
94
#[ derive( Debug , Clone ) ]
95
95
pub ( super ) struct NestedGoals < ' tcx > {
96
- /// This normalizes-to goal that is treated specially during the evaluation
96
+ /// These normalizes-to goals are treated specially during the evaluation
97
97
/// loop. In each iteration we take the RHS of the projection, replace it with
98
98
/// a fresh inference variable, and only after evaluating that goal do we
99
99
/// equate the fresh inference variable with the actual RHS of the predicate.
100
100
///
101
101
/// This is both to improve caching, and to avoid using the RHS of the
102
102
/// projection predicate to influence the normalizes-to candidate we select.
103
103
///
104
- /// This is not a 'real' nested goal. We must not forget to replace the RHS
105
- /// with a fresh inference variable when we evaluate this goal. That can result
106
- /// in a trait solver cycle. This would currently result in overflow but can be
107
- /// can be unsound with more powerful coinduction in the future.
108
- pub ( super ) normalizes_to_hack_goal : Option < Goal < ' tcx , ty:: NormalizesTo < ' tcx > > > ,
104
+ /// Forgetting to replace the RHS with a fresh inference variable when we evaluate
105
+ /// this goal results in an ICE..
106
+ pub ( super ) normalizes_to_goals : Vec < Goal < ' tcx , ty:: NormalizesTo < ' tcx > > > ,
109
107
/// The rest of the goals which have not yet processed or remain ambiguous.
110
108
pub ( super ) goals : Vec < ( GoalSource , Goal < ' tcx , ty:: Predicate < ' tcx > > ) > ,
111
109
}
112
110
113
111
impl < ' tcx > NestedGoals < ' tcx > {
114
112
pub ( super ) fn new ( ) -> Self {
115
- Self { normalizes_to_hack_goal : None , goals : Vec :: new ( ) }
113
+ Self { normalizes_to_goals : Vec :: new ( ) , goals : Vec :: new ( ) }
116
114
}
117
115
118
116
pub ( super ) fn is_empty ( & self ) -> bool {
119
- self . normalizes_to_hack_goal . is_none ( ) && self . goals . is_empty ( )
117
+ self . normalizes_to_goals . is_empty ( ) && self . goals . is_empty ( )
120
118
}
121
119
122
120
pub ( super ) fn extend ( & mut self , other : NestedGoals < ' tcx > ) {
123
- assert_eq ! ( other. normalizes_to_hack_goal , None ) ;
121
+ self . normalizes_to_goals . extend ( other. normalizes_to_goals ) ;
124
122
self . goals . extend ( other. goals )
125
123
}
126
124
}
@@ -508,7 +506,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
508
506
509
507
// If this loop did not result in any progress, what's our final certainty.
510
508
let mut unchanged_certainty = Some ( Certainty :: Yes ) ;
511
- if let Some ( goal) = goals. normalizes_to_hack_goal . take ( ) {
509
+ for goal in goals. normalizes_to_goals {
512
510
// Replace the goal with an unconstrained infer var, so the
513
511
// RHS does not affect projection candidate assembly.
514
512
let unconstrained_rhs = self . next_term_infer_of_kind ( goal. predicate . term ) ;
@@ -536,22 +534,21 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
536
534
// looking at the "has changed" return from evaluate_goal,
537
535
// because we expect the `unconstrained_rhs` part of the predicate
538
536
// to have changed -- that means we actually normalized successfully!
539
- if goal. predicate . alias != self . resolve_vars_if_possible ( goal. predicate . alias ) {
537
+ let with_resolved_vars = self . resolve_vars_if_possible ( goal) ;
538
+ if goal. predicate . alias != with_resolved_vars. predicate . alias {
540
539
unchanged_certainty = None ;
541
540
}
542
541
543
542
match certainty {
544
543
Certainty :: Yes => { }
545
544
Certainty :: Maybe ( _) => {
546
- // We need to resolve vars here so that we correctly
547
- // deal with `has_changed` in the next iteration.
548
- self . set_normalizes_to_hack_goal ( self . resolve_vars_if_possible ( goal) ) ;
545
+ self . nested_goals . normalizes_to_goals . push ( with_resolved_vars) ;
549
546
unchanged_certainty = unchanged_certainty. map ( |c| c. unify_with ( certainty) ) ;
550
547
}
551
548
}
552
549
}
553
550
554
- for ( source, goal) in goals. goals . drain ( .. ) {
551
+ for ( source, goal) in goals. goals {
555
552
let ( has_changed, certainty) = self . evaluate_goal (
556
553
GoalEvaluationKind :: Nested { is_normalizes_to_hack : IsNormalizesToHack :: No } ,
557
554
source,
0 commit comments