@@ -388,44 +388,60 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
388
388
&& is_normalizes_to_hack == IsNormalizesToHack :: No
389
389
&& !self . search_graph . in_cycle ( )
390
390
{
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) ;
424
399
}
425
400
426
401
Ok ( ( has_changed, certainty, nested_goals) )
427
402
}
428
403
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
+
429
445
fn compute_goal ( & mut self , goal : Goal < ' tcx , ty:: Predicate < ' tcx > > ) -> QueryResult < ' tcx > {
430
446
let Goal { param_env, predicate } = goal;
431
447
let kind = predicate. kind ( ) ;
0 commit comments