Skip to content

Commit f2f4152

Browse files
authored
Rollup merge of rust-lang#140305 - compiler-errors:coerce-loop, r=lcnr
Track per-obligation recursion depth only if there is inference in the new solver Track how many times an obligation has been processed in the fulfillment context by reusing its recursion depth, and only overflow if a singular (root) goal hits the limit. This also fixes a (probably theoretical at this point) problem where we don't detect pseudo-hangs across `select_where_possible` calls. fixes rust-lang/trait-system-refactor-initiative#186 r? lcnr
2 parents 6f6fa0f + 31c8d10 commit f2f4152

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)