lower evaluate_goal
stability check to warn
This commit is contained in:
parent
9eeaf1fd13
commit
51762886f6
@ -388,44 +388,60 @@ fn evaluate_goal(
|
|||||||
&& is_normalizes_to_hack == IsNormalizesToHack::No
|
&& is_normalizes_to_hack == IsNormalizesToHack::No
|
||||||
&& !self.search_graph.in_cycle()
|
&& !self.search_graph.in_cycle()
|
||||||
{
|
{
|
||||||
debug!("rerunning goal to check result is stable");
|
// The nested evaluation has to happen with the original state
|
||||||
|
// of `encountered_overflow`.
|
||||||
|
let from_original_evaluation =
|
||||||
self.search_graph.reset_encountered_overflow(encountered_overflow);
|
self.search_graph.reset_encountered_overflow(encountered_overflow);
|
||||||
|
self.check_evaluate_goal_stable_result(goal, canonical_goal, canonical_response);
|
||||||
|
// In case the evaluation was unstable, we manually make sure that this
|
||||||
|
// debug check does not influence the result of the parent goal.
|
||||||
|
self.search_graph.reset_encountered_overflow(from_original_evaluation);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((has_changed, certainty, nested_goals))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_evaluate_goal_stable_result(
|
||||||
|
&mut self,
|
||||||
|
goal: Goal<'tcx, ty::Predicate<'tcx>>,
|
||||||
|
original_input: CanonicalInput<'tcx>,
|
||||||
|
original_result: CanonicalResponse<'tcx>,
|
||||||
|
) {
|
||||||
let (_orig_values, canonical_goal) = self.canonicalize_goal(goal);
|
let (_orig_values, canonical_goal) = self.canonicalize_goal(goal);
|
||||||
let Ok(new_canonical_response) = EvalCtxt::evaluate_canonical_goal(
|
let result = EvalCtxt::evaluate_canonical_goal(
|
||||||
self.tcx(),
|
self.tcx(),
|
||||||
self.search_graph,
|
self.search_graph,
|
||||||
canonical_goal,
|
canonical_goal,
|
||||||
// FIXME(-Ztrait-solver=next): we do not track what happens in `evaluate_canonical_goal`
|
// FIXME(-Ztrait-solver=next): we do not track what happens in `evaluate_canonical_goal`
|
||||||
&mut ProofTreeBuilder::new_noop(),
|
&mut ProofTreeBuilder::new_noop(),
|
||||||
) else {
|
|
||||||
bug!(
|
|
||||||
"goal went from {certainty:?} to error: re-canonicalized goal={canonical_goal:#?} \
|
|
||||||
first_response={canonical_response:#?},
|
|
||||||
second response was error"
|
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
macro_rules! fail {
|
||||||
|
($msg:expr) => {{
|
||||||
|
let msg = $msg;
|
||||||
|
warn!(
|
||||||
|
"unstable result: {msg}\n\
|
||||||
|
original goal: {original_input:?},\n\
|
||||||
|
original result: {original_result:?}\n\
|
||||||
|
re-canonicalized goal: {canonical_goal:?}\n\
|
||||||
|
second response: {result:?}"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
let Ok(new_canonical_response) = result else { fail!("second response was error") };
|
||||||
// We only check for modulo regions as we convert all regions in
|
// We only check for modulo regions as we convert all regions in
|
||||||
// the input to new existentials, even if they're expected to be
|
// the input to new existentials, even if they're expected to be
|
||||||
// `'static` or a placeholder region.
|
// `'static` or a placeholder region.
|
||||||
if !new_canonical_response.value.var_values.is_identity_modulo_regions() {
|
if !new_canonical_response.value.var_values.is_identity_modulo_regions() {
|
||||||
bug!(
|
fail!("additional constraints from second response")
|
||||||
"unstable result: re-canonicalized goal={canonical_goal:#?} \
|
|
||||||
first_response={canonical_response:#?} \
|
|
||||||
second_response={new_canonical_response:#?}"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if certainty != new_canonical_response.value.certainty {
|
if original_result.value.certainty != new_canonical_response.value.certainty {
|
||||||
bug!(
|
fail!("unstable certainty")
|
||||||
"unstable certainty: {certainty:#?} re-canonicalized goal={canonical_goal:#?} \
|
|
||||||
first_response={canonical_response:#?} \
|
|
||||||
second_response={new_canonical_response:#?}"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((has_changed, certainty, nested_goals))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult<'tcx> {
|
fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult<'tcx> {
|
||||||
let Goal { param_env, predicate } = goal;
|
let Goal { param_env, predicate } = goal;
|
||||||
let kind = predicate.kind();
|
let kind = predicate.kind();
|
||||||
|
@ -134,9 +134,13 @@ pub(super) fn encountered_overflow(&self) -> bool {
|
|||||||
/// Resets `encountered_overflow` of the current goal.
|
/// Resets `encountered_overflow` of the current goal.
|
||||||
///
|
///
|
||||||
/// This should only be used for the check in `evaluate_goal`.
|
/// This should only be used for the check in `evaluate_goal`.
|
||||||
pub(super) fn reset_encountered_overflow(&mut self, encountered_overflow: bool) {
|
pub(super) fn reset_encountered_overflow(&mut self, encountered_overflow: bool) -> bool {
|
||||||
if encountered_overflow {
|
if let Some(last) = self.stack.raw.last_mut() {
|
||||||
self.stack.raw.last_mut().unwrap().encountered_overflow = true;
|
let prev = last.encountered_overflow;
|
||||||
|
last.encountered_overflow = encountered_overflow;
|
||||||
|
prev
|
||||||
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user