@@ -388,44 +388,60 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
388388 && is_normalizes_to_hack == IsNormalizesToHack :: No
389389 && !self . search_graph . in_cycle ( )
390390 {
391- debug ! ( "rerunning goal to check result is stable" ) ;
392- self . search_graph . reset_encountered_overflow ( encountered_overflow) ;
393- let ( _orig_values, canonical_goal) = self . canonicalize_goal ( goal) ;
394- let Ok ( new_canonical_response) = EvalCtxt :: evaluate_canonical_goal (
395- self . tcx ( ) ,
396- self . search_graph ,
397- canonical_goal,
398- // FIXME(-Ztrait-solver=next): we do not track what happens in `evaluate_canonical_goal`
399- & mut ProofTreeBuilder :: new_noop ( ) ,
400- ) else {
401- bug ! (
402- "goal went from {certainty:?} to error: re-canonicalized goal={canonical_goal:#?} \
403- first_response={canonical_response:#?},
404- second response was error"
405- ) ;
406- } ;
407- // We only check for modulo regions as we convert all regions in
408- // the input to new existentials, even if they're expected to be
409- // `'static` or a placeholder region.
410- if !new_canonical_response. value . var_values . is_identity_modulo_regions ( ) {
411- bug ! (
412- "unstable result: re-canonicalized goal={canonical_goal:#?} \
413- first_response={canonical_response:#?} \
414- second_response={new_canonical_response:#?}"
415- ) ;
416- }
417- if certainty != new_canonical_response. value . certainty {
418- bug ! (
419- "unstable certainty: {certainty:#?} re-canonicalized goal={canonical_goal:#?} \
420- first_response={canonical_response:#?} \
421- second_response={new_canonical_response:#?}"
422- ) ;
423- }
391+ // The nested evaluation has to happen with the original state
392+ // of `encountered_overflow`.
393+ let from_original_evaluation =
394+ self . search_graph . reset_encountered_overflow ( encountered_overflow) ;
395+ self . check_evaluate_goal_stable_result ( goal, canonical_goal, canonical_response) ;
396+ // In case the evaluation was unstable, we manually make sure that this
397+ // debug check does not influence the result of the parent goal.
398+ self . search_graph . reset_encountered_overflow ( from_original_evaluation) ;
424399 }
425400
426401 Ok ( ( has_changed, certainty, nested_goals) )
427402 }
428403
404+ fn check_evaluate_goal_stable_result (
405+ & mut self ,
406+ goal : Goal < ' tcx , ty:: Predicate < ' tcx > > ,
407+ original_input : CanonicalInput < ' tcx > ,
408+ original_result : CanonicalResponse < ' tcx > ,
409+ ) {
410+ let ( _orig_values, canonical_goal) = self . canonicalize_goal ( goal) ;
411+ let result = EvalCtxt :: evaluate_canonical_goal (
412+ self . tcx ( ) ,
413+ self . search_graph ,
414+ canonical_goal,
415+ // FIXME(-Ztrait-solver=next): we do not track what happens in `evaluate_canonical_goal`
416+ & mut ProofTreeBuilder :: new_noop ( ) ,
417+ ) ;
418+
419+ macro_rules! fail {
420+ ( $msg: expr) => { {
421+ let msg = $msg;
422+ warn!(
423+ "unstable result: {msg}\n \
424+ original goal: {original_input:?},\n \
425+ original result: {original_result:?}\n \
426+ re-canonicalized goal: {canonical_goal:?}\n \
427+ second response: {result:?}"
428+ ) ;
429+ return ;
430+ } } ;
431+ }
432+
433+ let Ok ( new_canonical_response) = result else { fail ! ( "second response was error" ) } ;
434+ // We only check for modulo regions as we convert all regions in
435+ // the input to new existentials, even if they're expected to be
436+ // `'static` or a placeholder region.
437+ if !new_canonical_response. value . var_values . is_identity_modulo_regions ( ) {
438+ fail ! ( "additional constraints from second response" )
439+ }
440+ if original_result. value . certainty != new_canonical_response. value . certainty {
441+ fail ! ( "unstable certainty" )
442+ }
443+ }
444+
429445 fn compute_goal ( & mut self , goal : Goal < ' tcx , ty:: Predicate < ' tcx > > ) -> QueryResult < ' tcx > {
430446 let Goal { param_env, predicate } = goal;
431447 let kind = predicate. kind ( ) ;
0 commit comments