11use std:: mem;
2- use std:: ops:: ControlFlow ;
32
43#[ cfg( feature = "nightly" ) ]
54use rustc_macros:: HashStable_NoContext ;
@@ -11,8 +10,7 @@ use rustc_type_ir::search_graph::{CandidateHeadUsages, PathKind};
1110use rustc_type_ir:: solve:: OpaqueTypesJank ;
1211use rustc_type_ir:: {
1312 self as ty, CanonicalVarValues , InferCtxtLike , Interner , TypeFoldable , TypeFolder ,
14- TypeSuperFoldable , TypeSuperVisitable , TypeVisitable , TypeVisitableExt , TypeVisitor ,
15- TypingMode ,
13+ TypeSuperFoldable , TypeVisitableExt , TypingMode ,
1614} ;
1715use tracing:: { debug, instrument, trace} ;
1816
@@ -47,13 +45,13 @@ enum CurrentGoalKind {
4745 /// These are currently the only goals whose impl where-clauses are considered to be
4846 /// productive steps.
4947 CoinductiveTrait ,
50- /// Unlike other goals, `NormalizesTo` goals act like functions with the expected term
51- /// always being fully unconstrained. This would weaken inference however, as the nested
48+ /// When probing and selecting `NormalizesTo` goal's projection candidates, the expected
49+ /// term is always fully unconstrained. This would weaken inference however, as the nested
5250 /// goals never get the inference constraints from the actual normalized-to type.
5351 ///
54- /// Because of this we return any ambiguous nested goals from `NormalizesTo` to the
55- /// caller when then adds these to its own context. The caller is always an `AliasRelate`
56- /// goal so this never leaks out of the solver.
52+ /// Because of this we return any ambiguous nested goals from the candidate probe to the
53+ /// root of the `NormalizesTo` goal then adds these to its own context. So this never leaks
54+ /// out of the solver.
5755 NormalizesTo ,
5856}
5957
@@ -67,7 +65,6 @@ impl CurrentGoalKind {
6765 CurrentGoalKind :: Misc
6866 }
6967 }
70- ty:: PredicateKind :: NormalizesTo ( _) => CurrentGoalKind :: NormalizesTo ,
7168 _ => CurrentGoalKind :: Misc ,
7269 }
7370 }
@@ -509,17 +506,6 @@ where
509506 HasChanged :: No => {
510507 let mut stalled_vars = orig_values;
511508
512- // Remove the unconstrained RHS arg, which is expected to have changed.
513- if let Some ( normalizes_to) = goal. predicate . as_normalizes_to ( ) {
514- let normalizes_to = normalizes_to. skip_binder ( ) ;
515- let rhs_arg: I :: GenericArg = normalizes_to. term . into ( ) ;
516- let idx = stalled_vars
517- . iter ( )
518- . rposition ( |arg| * arg == rhs_arg)
519- . expect ( "expected unconstrained arg" ) ;
520- stalled_vars. swap_remove ( idx) ;
521- }
522-
523509 // Remove the canonicalized universal vars, since we only care about stalled existentials.
524510 let mut sub_roots = Vec :: new ( ) ;
525511 stalled_vars. retain ( |arg| match arg. kind ( ) {
@@ -564,7 +550,12 @@ where
564550 pub ( super ) fn compute_goal ( & mut self , goal : Goal < I , I :: Predicate > ) -> QueryResult < I > {
565551 let Goal { param_env, predicate } = goal;
566552 let kind = predicate. kind ( ) ;
567- self . enter_forall ( kind, |ecx, kind| match kind {
553+
554+ if let Some ( normalizes_to) = predicate. as_normalizes_to ( ) {
555+ assert ! ( !normalizes_to. skip_binder( ) . has_escaping_bound_vars( ) ) ;
556+ }
557+
558+ let resp = self . enter_forall ( kind, |ecx, kind| match kind {
568559 ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Trait ( predicate) ) => {
569560 ecx. compute_trait_goal ( Goal { param_env, predicate } ) . map ( |( r, _via) | r)
570561 }
@@ -613,7 +604,11 @@ where
613604 ty:: PredicateKind :: Ambiguous => {
614605 ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: AMBIGUOUS )
615606 }
616- } )
607+ } ) ?;
608+
609+ assert ! ( resp. value. external_constraints. normalization_nested_goals. is_empty( ) ) ;
610+
611+ Ok ( resp)
617612 }
618613
619614 // Recursively evaluates all the goals added to this `EvalCtxt` to completion, returning
@@ -639,7 +634,6 @@ where
639634 ///
640635 /// Goals for the next step get directly added to the nested goals of the `EvalCtxt`.
641636 fn evaluate_added_goals_step ( & mut self ) -> Result < Option < Certainty > , NoSolution > {
642- let cx = self . cx ( ) ;
643637 // If this loop did not result in any progress, what's our final certainty.
644638 let mut unchanged_certainty = Some ( Certainty :: Yes ) ;
645639 for ( source, goal, stalled_on) in mem:: take ( & mut self . nested_goals ) {
@@ -654,92 +648,17 @@ where
654648 continue ;
655649 }
656650
657- // We treat normalizes-to goals specially here. In each iteration we take the
658- // RHS of the projection, replace it with a fresh inference variable, and only
659- // after evaluating that goal do we equate the fresh inference variable with the
660- // actual RHS of the predicate.
661- //
662- // This is both to improve caching, and to avoid using the RHS of the
663- // projection predicate to influence the normalizes-to candidate we select.
664- //
665- // Forgetting to replace the RHS with a fresh inference variable when we evaluate
666- // this goal results in an ICE.
667- if let Some ( pred) = goal. predicate . as_normalizes_to ( ) {
668- // We should never encounter higher-ranked normalizes-to goals.
669- let pred = pred. no_bound_vars ( ) . unwrap ( ) ;
670- // Replace the goal with an unconstrained infer var, so the
671- // RHS does not affect projection candidate assembly.
672- let unconstrained_rhs = self . next_term_infer_of_kind ( pred. term ) ;
673- let unconstrained_goal =
674- goal. with ( cx, ty:: NormalizesTo { alias : pred. alias , term : unconstrained_rhs } ) ;
675-
676- let (
677- NestedNormalizationGoals ( nested_goals) ,
678- GoalEvaluation { goal, certainty, stalled_on, has_changed : _ } ,
679- ) = self . evaluate_goal_raw ( source, unconstrained_goal, stalled_on) ?;
680- // Add the nested goals from normalization to our own nested goals.
681- trace ! ( ?nested_goals) ;
682- self . nested_goals . extend ( nested_goals. into_iter ( ) . map ( |( s, g) | ( s, g, None ) ) ) ;
683-
684- // Finally, equate the goal's RHS with the unconstrained var.
685- //
686- // SUBTLE:
687- // We structurally relate aliases here. This is necessary
688- // as we otherwise emit a nested `AliasRelate` goal in case the
689- // returned term is a rigid alias, resulting in overflow.
690- //
691- // It is correct as both `goal.predicate.term` and `unconstrained_rhs`
692- // start out as an unconstrained inference variable so any aliases get
693- // fully normalized when instantiating it.
694- //
695- // FIXME: Strictly speaking this may be incomplete if the normalized-to
696- // type contains an ambiguous alias referencing bound regions. We should
697- // consider changing this to only use "shallow structural equality".
698- self . eq_structurally_relating_aliases (
699- goal. param_env ,
700- pred. term ,
701- unconstrained_rhs,
702- ) ?;
703-
704- // We only look at the `projection_ty` part here rather than
705- // looking at the "has changed" return from evaluate_goal,
706- // because we expect the `unconstrained_rhs` part of the predicate
707- // to have changed -- that means we actually normalized successfully!
708- // FIXME: Do we need to eagerly resolve here? Or should we check
709- // if the cache key has any changed vars?
710- let with_resolved_vars = self . resolve_vars_if_possible ( goal) ;
711- if pred. alias
712- != with_resolved_vars
713- . predicate
714- . as_normalizes_to ( )
715- . unwrap ( )
716- . no_bound_vars ( )
717- . unwrap ( )
718- . alias
719- {
720- unchanged_certainty = None ;
721- }
722-
723- match certainty {
724- Certainty :: Yes => { }
725- Certainty :: Maybe { .. } => {
726- self . nested_goals . push ( ( source, with_resolved_vars, stalled_on) ) ;
727- unchanged_certainty = unchanged_certainty. map ( |c| c. and ( certainty) ) ;
728- }
729- }
730- } else {
731- let GoalEvaluation { goal, certainty, has_changed, stalled_on } =
732- self . evaluate_goal ( source, goal, stalled_on) ?;
733- if has_changed == HasChanged :: Yes {
734- unchanged_certainty = None ;
735- }
651+ let GoalEvaluation { goal, certainty, has_changed, stalled_on } =
652+ self . evaluate_goal ( source, goal, stalled_on) ?;
653+ if has_changed == HasChanged :: Yes {
654+ unchanged_certainty = None ;
655+ }
736656
737- match certainty {
738- Certainty :: Yes => { }
739- Certainty :: Maybe { .. } => {
740- self . nested_goals . push ( ( source, goal, stalled_on) ) ;
741- unchanged_certainty = unchanged_certainty. map ( |c| c. and ( certainty) ) ;
742- }
657+ match certainty {
658+ Certainty :: Yes => { }
659+ Certainty :: Maybe { .. } => {
660+ self . nested_goals . push ( ( source, goal, stalled_on) ) ;
661+ unchanged_certainty = unchanged_certainty. map ( |c| c. and ( certainty) ) ;
743662 }
744663 }
745664 }
@@ -802,129 +721,6 @@ where
802721 }
803722 }
804723
805- /// Is the projection predicate is of the form `exists<T> <Ty as Trait>::Assoc = T`.
806- ///
807- /// This is the case if the `term` does not occur in any other part of the predicate
808- /// and is able to name all other placeholder and inference variables.
809- #[ instrument( level = "trace" , skip( self ) , ret) ]
810- pub ( super ) fn term_is_fully_unconstrained ( & self , goal : Goal < I , ty:: NormalizesTo < I > > ) -> bool {
811- let universe_of_term = match goal. predicate . term . kind ( ) {
812- ty:: TermKind :: Ty ( ty) => {
813- if let ty:: Infer ( ty:: TyVar ( vid) ) = ty. kind ( ) {
814- self . delegate . universe_of_ty ( vid) . unwrap ( )
815- } else {
816- return false ;
817- }
818- }
819- ty:: TermKind :: Const ( ct) => {
820- if let ty:: ConstKind :: Infer ( ty:: InferConst :: Var ( vid) ) = ct. kind ( ) {
821- self . delegate . universe_of_ct ( vid) . unwrap ( )
822- } else {
823- return false ;
824- }
825- }
826- } ;
827-
828- struct ContainsTermOrNotNameable < ' a , D : SolverDelegate < Interner = I > , I : Interner > {
829- term : I :: Term ,
830- universe_of_term : ty:: UniverseIndex ,
831- delegate : & ' a D ,
832- cache : HashSet < I :: Ty > ,
833- }
834-
835- impl < D : SolverDelegate < Interner = I > , I : Interner > ContainsTermOrNotNameable < ' _ , D , I > {
836- fn check_nameable ( & self , universe : ty:: UniverseIndex ) -> ControlFlow < ( ) > {
837- if self . universe_of_term . can_name ( universe) {
838- ControlFlow :: Continue ( ( ) )
839- } else {
840- ControlFlow :: Break ( ( ) )
841- }
842- }
843- }
844-
845- impl < D : SolverDelegate < Interner = I > , I : Interner > TypeVisitor < I >
846- for ContainsTermOrNotNameable < ' _ , D , I >
847- {
848- type Result = ControlFlow < ( ) > ;
849- fn visit_ty ( & mut self , t : I :: Ty ) -> Self :: Result {
850- if self . cache . contains ( & t) {
851- return ControlFlow :: Continue ( ( ) ) ;
852- }
853-
854- match t. kind ( ) {
855- ty:: Infer ( ty:: TyVar ( vid) ) => {
856- if let ty:: TermKind :: Ty ( term) = self . term . kind ( )
857- && let ty:: Infer ( ty:: TyVar ( term_vid) ) = term. kind ( )
858- && self . delegate . root_ty_var ( vid) == self . delegate . root_ty_var ( term_vid)
859- {
860- return ControlFlow :: Break ( ( ) ) ;
861- }
862-
863- self . check_nameable ( self . delegate . universe_of_ty ( vid) . unwrap ( ) ) ?;
864- }
865- ty:: Placeholder ( p) => self . check_nameable ( p. universe ( ) ) ?,
866- _ => {
867- if t. has_non_region_infer ( ) || t. has_placeholders ( ) {
868- t. super_visit_with ( self ) ?
869- }
870- }
871- }
872-
873- assert ! ( self . cache. insert( t) ) ;
874- ControlFlow :: Continue ( ( ) )
875- }
876-
877- fn visit_const ( & mut self , c : I :: Const ) -> Self :: Result {
878- match c. kind ( ) {
879- ty:: ConstKind :: Infer ( ty:: InferConst :: Var ( vid) ) => {
880- if let ty:: TermKind :: Const ( term) = self . term . kind ( )
881- && let ty:: ConstKind :: Infer ( ty:: InferConst :: Var ( term_vid) ) = term. kind ( )
882- && self . delegate . root_const_var ( vid)
883- == self . delegate . root_const_var ( term_vid)
884- {
885- return ControlFlow :: Break ( ( ) ) ;
886- }
887-
888- self . check_nameable ( self . delegate . universe_of_ct ( vid) . unwrap ( ) )
889- }
890- ty:: ConstKind :: Placeholder ( p) => self . check_nameable ( p. universe ( ) ) ,
891- _ => {
892- if c. has_non_region_infer ( ) || c. has_placeholders ( ) {
893- c. super_visit_with ( self )
894- } else {
895- ControlFlow :: Continue ( ( ) )
896- }
897- }
898- }
899- }
900-
901- fn visit_predicate ( & mut self , p : I :: Predicate ) -> Self :: Result {
902- if p. has_non_region_infer ( ) || p. has_placeholders ( ) {
903- p. super_visit_with ( self )
904- } else {
905- ControlFlow :: Continue ( ( ) )
906- }
907- }
908-
909- fn visit_clauses ( & mut self , c : I :: Clauses ) -> Self :: Result {
910- if c. has_non_region_infer ( ) || c. has_placeholders ( ) {
911- c. super_visit_with ( self )
912- } else {
913- ControlFlow :: Continue ( ( ) )
914- }
915- }
916- }
917-
918- let mut visitor = ContainsTermOrNotNameable {
919- delegate : self . delegate ,
920- universe_of_term,
921- term : goal. predicate . term ,
922- cache : Default :: default ( ) ,
923- } ;
924- goal. predicate . alias . visit_with ( & mut visitor) . is_continue ( )
925- && goal. param_env . visit_with ( & mut visitor) . is_continue ( )
926- }
927-
928724 pub ( super ) fn sub_unify_ty_vids_raw ( & self , a : ty:: TyVid , b : ty:: TyVid ) {
929725 self . delegate . sub_unify_ty_vids_raw ( a, b)
930726 }
0 commit comments