@@ -23,14 +23,15 @@ use rustc_middle::ty::{
2323use rustc_session:: config:: DumpSolverProofTree ;
2424use rustc_span:: DUMMY_SP ;
2525use std:: io:: Write ;
26+ use std:: iter;
2627use std:: ops:: ControlFlow ;
2728
2829use crate :: traits:: vtable:: { count_own_vtable_entries, prepare_vtable_segments, VtblSegment } ;
2930
3031use super :: inspect:: ProofTreeBuilder ;
31- use super :: SolverMode ;
3232use super :: { search_graph, GoalEvaluationKind } ;
3333use super :: { search_graph:: SearchGraph , Goal } ;
34+ use super :: { GoalSource , SolverMode } ;
3435pub use select:: InferCtxtSelectExt ;
3536
3637mod canonical;
@@ -105,7 +106,7 @@ pub(super) struct NestedGoals<'tcx> {
105106 /// can be unsound with more powerful coinduction in the future.
106107 pub ( super ) normalizes_to_hack_goal : Option < Goal < ' tcx , ty:: NormalizesTo < ' tcx > > > ,
107108 /// The rest of the goals which have not yet processed or remain ambiguous.
108- pub ( super ) goals : Vec < Goal < ' tcx , ty:: Predicate < ' tcx > > > ,
109+ pub ( super ) goals : Vec < ( GoalSource , Goal < ' tcx , ty:: Predicate < ' tcx > > ) > ,
109110}
110111
111112impl < ' tcx > NestedGoals < ' tcx > {
@@ -156,7 +157,7 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
156157 Option < inspect:: GoalEvaluation < ' tcx > > ,
157158 ) {
158159 EvalCtxt :: enter_root ( self , generate_proof_tree, |ecx| {
159- ecx. evaluate_goal ( GoalEvaluationKind :: Root , goal)
160+ ecx. evaluate_goal ( GoalEvaluationKind :: Root , GoalSource :: Misc , goal)
160161 } )
161162 }
162163}
@@ -334,6 +335,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
334335 fn evaluate_goal (
335336 & mut self ,
336337 goal_evaluation_kind : GoalEvaluationKind ,
338+ source : GoalSource ,
337339 goal : Goal < ' tcx , ty:: Predicate < ' tcx > > ,
338340 ) -> Result < ( bool , Certainty , Vec < Goal < ' tcx , ty:: Predicate < ' tcx > > > ) , NoSolution > {
339341 let ( orig_values, canonical_goal) = self . canonicalize_goal ( goal) ;
@@ -353,13 +355,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
353355 Ok ( response) => response,
354356 } ;
355357
356- let has_changed = !canonical_response . value . var_values . is_identity_modulo_regions ( )
357- || !canonical_response . value . external_constraints . opaque_types . is_empty ( ) ;
358- let ( certainty , nested_goals ) = match self . instantiate_and_apply_query_response (
359- goal . param_env ,
360- orig_values,
361- canonical_response,
362- ) {
358+ let ( certainty , has_changed, nested_goals ) = match self
359+ . instantiate_response_discarding_overflow (
360+ goal . param_env ,
361+ source ,
362+ orig_values,
363+ canonical_response,
364+ ) {
363365 Err ( e) => {
364366 self . inspect . goal_evaluation ( goal_evaluation) ;
365367 return Err ( e) ;
@@ -386,6 +388,44 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
386388 Ok ( ( has_changed, certainty, nested_goals) )
387389 }
388390
391+ fn instantiate_response_discarding_overflow (
392+ & mut self ,
393+ param_env : ty:: ParamEnv < ' tcx > ,
394+ source : GoalSource ,
395+ original_values : Vec < ty:: GenericArg < ' tcx > > ,
396+ response : CanonicalResponse < ' tcx > ,
397+ ) -> Result < ( Certainty , bool , Vec < Goal < ' tcx , ty:: Predicate < ' tcx > > > ) , NoSolution > {
398+ // The old solver did not evaluate nested goals when normalizing.
399+ // It returned the selection constraints allowing a `Projection`
400+ // obligation to not hold in coherence while avoiding the fatal error
401+ // from overflow.
402+ //
403+ // We match this behavior here by considering all constraints
404+ // from nested goals which are not from where-bounds. We will already
405+ // need to track which nested goals are required by impl where-bounds
406+ // for coinductive cycles, so we simply reuse that here.
407+ //
408+ // While we could consider overflow constraints in more cases, this should
409+ // not be necessary for backcompat and results in better perf. It also
410+ // avoids a potential inconsistency which would otherwise require some
411+ // tracking for root goals as well. See #119071 for an example.
412+ let keep_overflow_constraints = || {
413+ self . search_graph . current_goal_is_normalizes_to ( )
414+ && source != GoalSource :: ImplWhereBound
415+ } ;
416+
417+ if response. value . certainty == Certainty :: OVERFLOW && !keep_overflow_constraints ( ) {
418+ Ok ( ( Certainty :: OVERFLOW , false , Vec :: new ( ) ) )
419+ } else {
420+ let has_changed = !response. value . var_values . is_identity_modulo_regions ( )
421+ || !response. value . external_constraints . opaque_types . is_empty ( ) ;
422+
423+ let ( certainty, nested_goals) =
424+ self . instantiate_and_apply_query_response ( param_env, original_values, response) ?;
425+ Ok ( ( certainty, has_changed, nested_goals) )
426+ }
427+ }
428+
389429 fn compute_goal ( & mut self , goal : Goal < ' tcx , ty:: Predicate < ' tcx > > ) -> QueryResult < ' tcx > {
390430 let Goal { param_env, predicate } = goal;
391431 let kind = predicate. kind ( ) ;
@@ -439,7 +479,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
439479 } else {
440480 let kind = self . infcx . instantiate_binder_with_placeholders ( kind) ;
441481 let goal = goal. with ( self . tcx ( ) , ty:: Binder :: dummy ( kind) ) ;
442- self . add_goal ( goal) ;
482+ self . add_goal ( GoalSource :: Misc , goal) ;
443483 self . evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
444484 }
445485 }
@@ -488,6 +528,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
488528 let mut goals = core:: mem:: replace ( & mut self . nested_goals , NestedGoals :: new ( ) ) ;
489529
490530 self . inspect . evaluate_added_goals_loop_start ( ) ;
531+
532+ fn with_misc_source < ' tcx > (
533+ it : impl IntoIterator < Item = Goal < ' tcx , ty:: Predicate < ' tcx > > > ,
534+ ) -> impl Iterator < Item = ( GoalSource , Goal < ' tcx , ty:: Predicate < ' tcx > > ) > {
535+ iter:: zip ( iter:: repeat ( GoalSource :: Misc ) , it)
536+ }
537+
491538 // If this loop did not result in any progress, what's our final certainty.
492539 let mut unchanged_certainty = Some ( Certainty :: Yes ) ;
493540 if let Some ( goal) = goals. normalizes_to_hack_goal . take ( ) {
@@ -501,9 +548,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
501548
502549 let ( _, certainty, instantiate_goals) = self . evaluate_goal (
503550 GoalEvaluationKind :: Nested { is_normalizes_to_hack : IsNormalizesToHack :: Yes } ,
551+ GoalSource :: Misc ,
504552 unconstrained_goal,
505553 ) ?;
506- self . nested_goals . goals . extend ( instantiate_goals) ;
554+ self . nested_goals . goals . extend ( with_misc_source ( instantiate_goals) ) ;
507555
508556 // Finally, equate the goal's RHS with the unconstrained var.
509557 // We put the nested goals from this into goals instead of
@@ -512,7 +560,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
512560 // matters in practice, though.
513561 let eq_goals =
514562 self . eq_and_get_goals ( goal. param_env , goal. predicate . term , unconstrained_rhs) ?;
515- goals. goals . extend ( eq_goals) ;
563+ goals. goals . extend ( with_misc_source ( eq_goals) ) ;
516564
517565 // We only look at the `projection_ty` part here rather than
518566 // looking at the "has changed" return from evaluate_goal,
@@ -533,20 +581,21 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
533581 }
534582 }
535583
536- for goal in goals. goals . drain ( ..) {
584+ for ( source , goal) in goals. goals . drain ( ..) {
537585 let ( has_changed, certainty, instantiate_goals) = self . evaluate_goal (
538586 GoalEvaluationKind :: Nested { is_normalizes_to_hack : IsNormalizesToHack :: No } ,
587+ source,
539588 goal,
540589 ) ?;
541- self . nested_goals . goals . extend ( instantiate_goals) ;
590+ self . nested_goals . goals . extend ( with_misc_source ( instantiate_goals) ) ;
542591 if has_changed {
543592 unchanged_certainty = None ;
544593 }
545594
546595 match certainty {
547596 Certainty :: Yes => { }
548597 Certainty :: Maybe ( _) => {
549- self . nested_goals . goals . push ( goal) ;
598+ self . nested_goals . goals . push ( ( source , goal) ) ;
550599 unchanged_certainty = unchanged_certainty. map ( |c| c. unify_with ( certainty) ) ;
551600 }
552601 }
@@ -670,7 +719,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
670719 . at ( & ObligationCause :: dummy ( ) , param_env)
671720 . eq ( DefineOpaqueTypes :: No , lhs, rhs)
672721 . map ( |InferOk { value : ( ) , obligations } | {
673- self . add_goals ( obligations. into_iter ( ) . map ( |o| o. into ( ) ) ) ;
722+ self . add_goals ( GoalSource :: Misc , obligations. into_iter ( ) . map ( |o| o. into ( ) ) ) ;
674723 } )
675724 . map_err ( |e| {
676725 debug ! ( ?e, "failed to equate" ) ;
@@ -689,7 +738,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
689738 . at ( & ObligationCause :: dummy ( ) , param_env)
690739 . sub ( DefineOpaqueTypes :: No , sub, sup)
691740 . map ( |InferOk { value : ( ) , obligations } | {
692- self . add_goals ( obligations. into_iter ( ) . map ( |o| o. into ( ) ) ) ;
741+ self . add_goals ( GoalSource :: Misc , obligations. into_iter ( ) . map ( |o| o. into ( ) ) ) ;
693742 } )
694743 . map_err ( |e| {
695744 debug ! ( ?e, "failed to subtype" ) ;
@@ -709,7 +758,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
709758 . at ( & ObligationCause :: dummy ( ) , param_env)
710759 . relate ( DefineOpaqueTypes :: No , lhs, variance, rhs)
711760 . map ( |InferOk { value : ( ) , obligations } | {
712- self . add_goals ( obligations. into_iter ( ) . map ( |o| o. into ( ) ) ) ;
761+ self . add_goals ( GoalSource :: Misc , obligations. into_iter ( ) . map ( |o| o. into ( ) ) ) ;
713762 } )
714763 . map_err ( |e| {
715764 debug ! ( ?e, "failed to relate" ) ;
@@ -842,7 +891,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
842891 true ,
843892 & mut obligations,
844893 ) ?;
845- self . add_goals ( obligations. into_iter ( ) . map ( |o| o. into ( ) ) ) ;
894+ self . add_goals ( GoalSource :: Misc , obligations. into_iter ( ) . map ( |o| o. into ( ) ) ) ;
846895 Ok ( ( ) )
847896 }
848897
@@ -862,7 +911,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
862911 hidden_ty,
863912 & mut obligations,
864913 ) ;
865- self . add_goals ( obligations. into_iter ( ) . map ( |o| o. into ( ) ) ) ;
914+ self . add_goals ( GoalSource :: Misc , obligations. into_iter ( ) . map ( |o| o. into ( ) ) ) ;
866915 }
867916
868917 // Do something for each opaque/hidden pair defined with `def_id` in the
0 commit comments