Skip to content

Track per-obligation recursion depth only if there is inference in the new solver #140305

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions compiler/rustc_trait_selection/src/solve/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;
}

Expand Down
31 changes: 31 additions & 0 deletions tests/ui/traits/next-solver/coerce-depth.rs
Original file line number Diff line number Diff line change
@@ -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),
};
}
Loading