Skip to content

Commit 5176288

Browse files
committed
lower evaluate_goal stability check to warn
1 parent 9eeaf1f commit 5176288

File tree

2 files changed

+56
-36
lines changed

2 files changed

+56
-36
lines changed

compiler/rustc_trait_selection/src/solve/eval_ctxt.rs

+49-33
Original file line numberDiff line numberDiff line change
@@ -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();

compiler/rustc_trait_selection/src/solve/search_graph/mod.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,13 @@ impl<'tcx> SearchGraph<'tcx> {
134134
/// Resets `encountered_overflow` of the current goal.
135135
///
136136
/// This should only be used for the check in `evaluate_goal`.
137-
pub(super) fn reset_encountered_overflow(&mut self, encountered_overflow: bool) {
138-
if encountered_overflow {
139-
self.stack.raw.last_mut().unwrap().encountered_overflow = true;
137+
pub(super) fn reset_encountered_overflow(&mut self, encountered_overflow: bool) -> bool {
138+
if let Some(last) = self.stack.raw.last_mut() {
139+
let prev = last.encountered_overflow;
140+
last.encountered_overflow = encountered_overflow;
141+
prev
142+
} else {
143+
false
140144
}
141145
}
142146

0 commit comments

Comments
 (0)