Track per-obligation recursion depth only if there is inference

This commit is contained in:
Michael Goulet 2025-04-25 17:57:59 +00:00
parent 8f43b85954
commit 31c8d10342
2 changed files with 46 additions and 8 deletions

View file

@ -163,15 +163,15 @@ where
fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> {
assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots());
let mut errors = Vec::new();
for i in 0.. {
if !infcx.tcx.recursion_limit().value_within_limit(i) {
self.obligations.on_fulfillment_overflow(infcx);
// Only return true errors that we have accumulated while processing.
return errors;
}
loop {
let mut has_changed = false;
for obligation in self.obligations.drain_pending(|_| true) {
for mut obligation in self.obligations.drain_pending(|_| true) {
if !infcx.tcx.recursion_limit().value_within_limit(obligation.recursion_depth) {
self.obligations.on_fulfillment_overflow(infcx);
// Only return true errors that we have accumulated while processing.
return errors;
}
let goal = obligation.as_goal();
let result = <&SolverDelegate<'tcx>>::from(infcx)
.evaluate_root_goal(goal, GenerateProofTree::No, obligation.cause.span)
@ -189,6 +189,13 @@ where
};
if changed == HasChanged::Yes {
// We increment the recursion depth here to track the number of times
// this goal has resulted in inference progress. This doesn't precisely
// model the way that we track recursion depth in the old solver due
// to the fact that we only process root obligations, but it is a good
// approximation and should only result in fulfillment overflow in
// pathological cases.
obligation.recursion_depth += 1;
has_changed = true;
}

View file

@ -0,0 +1,31 @@
//@ check-pass
//@ compile-flags: -Znext-solver
// Ensure that a stack of coerce predicates doesn't end up overflowing when they get procesed
// in *reverse* order, which may require O(N) iterations of the fulfillment loop.
#![recursion_limit = "16"]
fn main() {
match 0 {
0 => None,
1 => None,
2 => None,
3 => None,
4 => None,
5 => None,
6 => None,
7 => None,
8 => None,
9 => None,
10 => None,
11 => None,
12 => None,
13 => None,
14 => None,
15 => None,
16 => None,
17 => None,
_ => Some(1u32),
};
}