1+ use std:: mem;
12use std:: ops:: ControlFlow ;
23
3- use derive_where:: derive_where;
44#[ cfg( feature = "nightly" ) ]
5- use rustc_macros:: { Decodable_NoContext , Encodable_NoContext , HashStable_NoContext } ;
5+ use rustc_macros:: HashStable_NoContext ;
66use rustc_type_ir:: data_structures:: { HashMap , HashSet , ensure_sufficient_stack} ;
77use rustc_type_ir:: fast_reject:: DeepRejectCtxt ;
88use rustc_type_ir:: inherent:: * ;
@@ -14,7 +14,6 @@ use rustc_type_ir::{
1414 TypeSuperFoldable , TypeSuperVisitable , TypeVisitable , TypeVisitableExt , TypeVisitor ,
1515 TypingMode ,
1616} ;
17- use rustc_type_ir_macros:: { Lift_Generic , TypeFoldable_Generic , TypeVisitable_Generic } ;
1817use tracing:: { instrument, trace} ;
1918
2019use crate :: coherence;
@@ -114,7 +113,7 @@ where
114113
115114 pub ( super ) search_graph : & ' a mut SearchGraph < D > ,
116115
117- nested_goals : NestedGoals < I > ,
116+ nested_goals : Vec < ( GoalSource , Goal < I , I :: Predicate > ) > ,
118117
119118 pub ( super ) origin_span : I :: Span ,
120119
@@ -129,38 +128,6 @@ where
129128 pub ( super ) inspect : ProofTreeBuilder < D > ,
130129}
131130
132- #[ derive_where( Clone , Debug , Default ; I : Interner ) ]
133- #[ derive( TypeVisitable_Generic , TypeFoldable_Generic , Lift_Generic ) ]
134- #[ cfg_attr(
135- feature = "nightly" ,
136- derive( Decodable_NoContext , Encodable_NoContext , HashStable_NoContext )
137- ) ]
138- struct NestedGoals < I : Interner > {
139- /// These normalizes-to goals are treated specially during the evaluation
140- /// loop. In each iteration we take the RHS of the projection, replace it with
141- /// a fresh inference variable, and only after evaluating that goal do we
142- /// equate the fresh inference variable with the actual RHS of the predicate.
143- ///
144- /// This is both to improve caching, and to avoid using the RHS of the
145- /// projection predicate to influence the normalizes-to candidate we select.
146- ///
147- /// Forgetting to replace the RHS with a fresh inference variable when we evaluate
148- /// this goal results in an ICE..
149- pub normalizes_to_goals : Vec < Goal < I , ty:: NormalizesTo < I > > > ,
150- /// The rest of the goals which have not yet processed or remain ambiguous.
151- pub goals : Vec < ( GoalSource , Goal < I , I :: Predicate > ) > ,
152- }
153-
154- impl < I : Interner > NestedGoals < I > {
155- fn new ( ) -> Self {
156- Self { normalizes_to_goals : Vec :: new ( ) , goals : Vec :: new ( ) }
157- }
158-
159- fn is_empty ( & self ) -> bool {
160- self . normalizes_to_goals . is_empty ( ) && self . goals . is_empty ( )
161- }
162- }
163-
164131#[ derive( PartialEq , Eq , Debug , Hash , Clone , Copy ) ]
165132#[ cfg_attr( feature = "nightly" , derive( HashStable_NoContext ) ) ]
166133pub enum GenerateProofTree {
@@ -332,7 +299,7 @@ where
332299 let mut ecx = EvalCtxt {
333300 delegate,
334301 search_graph : & mut search_graph,
335- nested_goals : NestedGoals :: new ( ) ,
302+ nested_goals : Default :: default ( ) ,
336303 inspect : ProofTreeBuilder :: new_maybe_root ( generate_proof_tree) ,
337304
338305 // Only relevant when canonicalizing the response,
@@ -385,7 +352,7 @@ where
385352 predefined_opaques_in_body : input. predefined_opaques_in_body ,
386353 max_input_universe : canonical_input. canonical . max_universe ,
387354 search_graph,
388- nested_goals : NestedGoals :: new ( ) ,
355+ nested_goals : Default :: default ( ) ,
389356 origin_span : I :: Span :: dummy ( ) ,
390357 tainted : Ok ( ( ) ) ,
391358 inspect : canonical_goal_evaluation. new_goal_evaluation_step ( var_values) ,
@@ -629,78 +596,83 @@ where
629596 /// Goals for the next step get directly added to the nested goals of the `EvalCtxt`.
630597 fn evaluate_added_goals_step ( & mut self ) -> Result < Option < Certainty > , NoSolution > {
631598 let cx = self . cx ( ) ;
632- let mut goals = core:: mem:: take ( & mut self . nested_goals ) ;
633-
634599 // If this loop did not result in any progress, what's our final certainty.
635600 let mut unchanged_certainty = Some ( Certainty :: Yes ) ;
636- for goal in goals. normalizes_to_goals {
637- // Replace the goal with an unconstrained infer var, so the
638- // RHS does not affect projection candidate assembly.
639- let unconstrained_rhs = self . next_term_infer_of_kind ( goal. predicate . term ) ;
640- let unconstrained_goal = goal. with (
641- cx,
642- ty:: NormalizesTo { alias : goal. predicate . alias , term : unconstrained_rhs } ,
643- ) ;
644-
645- let ( NestedNormalizationGoals ( nested_goals) , _, certainty) = self . evaluate_goal_raw (
646- GoalEvaluationKind :: Nested ,
647- GoalSource :: TypeRelating ,
648- unconstrained_goal,
649- ) ?;
650- // Add the nested goals from normalization to our own nested goals.
651- trace ! ( ?nested_goals) ;
652- goals. goals . extend ( nested_goals) ;
653-
654- // Finally, equate the goal's RHS with the unconstrained var.
601+ for ( source, goal) in mem:: take ( & mut self . nested_goals ) {
602+ // We treat normalizes-to goals specially here. In each iteration we take the
603+ // RHS of the projection, replace it with a fresh inference variable, and only
604+ // after evaluating that goal do we equate the fresh inference variable with the
605+ // actual RHS of the predicate.
655606 //
656- // SUBTLE:
657- // We structurally relate aliases here. This is necessary
658- // as we otherwise emit a nested `AliasRelate` goal in case the
659- // returned term is a rigid alias, resulting in overflow.
607+ // This is both to improve caching, and to avoid using the RHS of the
608+ // projection predicate to influence the normalizes-to candidate we select.
660609 //
661- // It is correct as both `goal.predicate.term` and `unconstrained_rhs`
662- // start out as an unconstrained inference variable so any aliases get
663- // fully normalized when instantiating it.
664- //
665- // FIXME: Strictly speaking this may be incomplete if the normalized-to
666- // type contains an ambiguous alias referencing bound regions. We should
667- // consider changing this to only use "shallow structural equality".
668- self . eq_structurally_relating_aliases (
669- goal. param_env ,
670- goal. predicate . term ,
671- unconstrained_rhs,
672- ) ?;
673-
674- // We only look at the `projection_ty` part here rather than
675- // looking at the "has changed" return from evaluate_goal,
676- // because we expect the `unconstrained_rhs` part of the predicate
677- // to have changed -- that means we actually normalized successfully!
678- let with_resolved_vars = self . resolve_vars_if_possible ( goal) ;
679- if goal. predicate . alias != with_resolved_vars. predicate . alias {
680- unchanged_certainty = None ;
681- }
682-
683- match certainty {
684- Certainty :: Yes => { }
685- Certainty :: Maybe ( _) => {
686- self . nested_goals . normalizes_to_goals . push ( with_resolved_vars) ;
687- unchanged_certainty = unchanged_certainty. map ( |c| c. unify_with ( certainty) ) ;
610+ // Forgetting to replace the RHS with a fresh inference variable when we evaluate
611+ // this goal results in an ICE.
612+ if let Some ( pred) = goal. predicate . as_normalizes_to ( ) {
613+ // We should never encounter higher-ranked normalizes-to goals.
614+ let pred = pred. no_bound_vars ( ) . unwrap ( ) ;
615+ // Replace the goal with an unconstrained infer var, so the
616+ // RHS does not affect projection candidate assembly.
617+ let unconstrained_rhs = self . next_term_infer_of_kind ( pred. term ) ;
618+ let unconstrained_goal =
619+ goal. with ( cx, ty:: NormalizesTo { alias : pred. alias , term : unconstrained_rhs } ) ;
620+
621+ let ( NestedNormalizationGoals ( nested_goals) , _, certainty) =
622+ self . evaluate_goal_raw ( GoalEvaluationKind :: Nested , source, unconstrained_goal) ?;
623+ // Add the nested goals from normalization to our own nested goals.
624+ trace ! ( ?nested_goals) ;
625+ self . nested_goals . extend ( nested_goals) ;
626+
627+ // Finally, equate the goal's RHS with the unconstrained var.
628+ //
629+ // SUBTLE:
630+ // We structurally relate aliases here. This is necessary
631+ // as we otherwise emit a nested `AliasRelate` goal in case the
632+ // returned term is a rigid alias, resulting in overflow.
633+ //
634+ // It is correct as both `goal.predicate.term` and `unconstrained_rhs`
635+ // start out as an unconstrained inference variable so any aliases get
636+ // fully normalized when instantiating it.
637+ //
638+ // FIXME: Strictly speaking this may be incomplete if the normalized-to
639+ // type contains an ambiguous alias referencing bound regions. We should
640+ // consider changing this to only use "shallow structural equality".
641+ self . eq_structurally_relating_aliases (
642+ goal. param_env ,
643+ pred. term ,
644+ unconstrained_rhs,
645+ ) ?;
646+
647+ // We only look at the `projection_ty` part here rather than
648+ // looking at the "has changed" return from evaluate_goal,
649+ // because we expect the `unconstrained_rhs` part of the predicate
650+ // to have changed -- that means we actually normalized successfully!
651+ let with_resolved_vars = self . resolve_vars_if_possible ( goal) ;
652+ if pred. alias != goal. predicate . as_normalizes_to ( ) . unwrap ( ) . skip_binder ( ) . alias {
653+ unchanged_certainty = None ;
688654 }
689- }
690- }
691655
692- for ( source, goal) in goals. goals {
693- let ( has_changed, certainty) =
694- self . evaluate_goal ( GoalEvaluationKind :: Nested , source, goal) ?;
695- if has_changed == HasChanged :: Yes {
696- unchanged_certainty = None ;
697- }
656+ match certainty {
657+ Certainty :: Yes => { }
658+ Certainty :: Maybe ( _) => {
659+ self . nested_goals . push ( ( source, with_resolved_vars) ) ;
660+ unchanged_certainty = unchanged_certainty. map ( |c| c. unify_with ( certainty) ) ;
661+ }
662+ }
663+ } else {
664+ let ( has_changed, certainty) =
665+ self . evaluate_goal ( GoalEvaluationKind :: Nested , source, goal) ?;
666+ if has_changed == HasChanged :: Yes {
667+ unchanged_certainty = None ;
668+ }
698669
699- match certainty {
700- Certainty :: Yes => { }
701- Certainty :: Maybe ( _) => {
702- self . nested_goals . goals . push ( ( source, goal) ) ;
703- unchanged_certainty = unchanged_certainty. map ( |c| c. unify_with ( certainty) ) ;
670+ match certainty {
671+ Certainty :: Yes => { }
672+ Certainty :: Maybe ( _) => {
673+ self . nested_goals . push ( ( source, goal) ) ;
674+ unchanged_certainty = unchanged_certainty. map ( |c| c. unify_with ( certainty) ) ;
675+ }
704676 }
705677 }
706678 }
@@ -717,23 +689,12 @@ where
717689 self . delegate . cx ( )
718690 }
719691
720- #[ instrument( level = "trace" , skip( self ) ) ]
721- pub ( super ) fn add_normalizes_to_goal ( & mut self , mut goal : Goal < I , ty:: NormalizesTo < I > > ) {
722- goal. predicate = goal. predicate . fold_with ( & mut ReplaceAliasWithInfer :: new (
723- self ,
724- GoalSource :: TypeRelating ,
725- goal. param_env ,
726- ) ) ;
727- self . inspect . add_normalizes_to_goal ( self . delegate , self . max_input_universe , goal) ;
728- self . nested_goals . normalizes_to_goals . push ( goal) ;
729- }
730-
731692 #[ instrument( level = "debug" , skip( self ) ) ]
732693 pub ( super ) fn add_goal ( & mut self , source : GoalSource , mut goal : Goal < I , I :: Predicate > ) {
733694 goal. predicate =
734695 goal. predicate . fold_with ( & mut ReplaceAliasWithInfer :: new ( self , source, goal. param_env ) ) ;
735696 self . inspect . add_goal ( self . delegate , self . max_input_universe , source, goal) ;
736- self . nested_goals . goals . push ( ( source, goal) ) ;
697+ self . nested_goals . push ( ( source, goal) ) ;
737698 }
738699
739700 #[ instrument( level = "trace" , skip( self , goals) ) ]
0 commit comments