Skip to content

Commit 31c8d10

Browse files
Track per-obligation recursion depth only if there is inference
1 parent 8f43b85 commit 31c8d10

File tree

2 files changed

+46
-8
lines changed

2 files changed

+46
-8
lines changed

compiler/rustc_trait_selection/src/solve/fulfill.rs

+15-8
Original file line numberDiff line numberDiff line change
@@ -163,15 +163,15 @@ where
163163
fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> {
164164
assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots());
165165
let mut errors = Vec::new();
166-
for i in 0.. {
167-
if !infcx.tcx.recursion_limit().value_within_limit(i) {
168-
self.obligations.on_fulfillment_overflow(infcx);
169-
// Only return true errors that we have accumulated while processing.
170-
return errors;
171-
}
172-
166+
loop {
173167
let mut has_changed = false;
174-
for obligation in self.obligations.drain_pending(|_| true) {
168+
for mut obligation in self.obligations.drain_pending(|_| true) {
169+
if !infcx.tcx.recursion_limit().value_within_limit(obligation.recursion_depth) {
170+
self.obligations.on_fulfillment_overflow(infcx);
171+
// Only return true errors that we have accumulated while processing.
172+
return errors;
173+
}
174+
175175
let goal = obligation.as_goal();
176176
let result = <&SolverDelegate<'tcx>>::from(infcx)
177177
.evaluate_root_goal(goal, GenerateProofTree::No, obligation.cause.span)
@@ -189,6 +189,13 @@ where
189189
};
190190

191191
if changed == HasChanged::Yes {
192+
// We increment the recursion depth here to track the number of times
193+
// this goal has resulted in inference progress. This doesn't precisely
194+
// model the way that we track recursion depth in the old solver due
195+
// to the fact that we only process root obligations, but it is a good
196+
// approximation and should only result in fulfillment overflow in
197+
// pathological cases.
198+
obligation.recursion_depth += 1;
192199
has_changed = true;
193200
}
194201

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

0 commit comments

Comments
 (0)