Skip to content

Commit c63861b

Browse files
committed
evaluate: improve and fix recursion depth handling
1 parent 791ce0b commit c63861b

File tree

9 files changed

+60
-95
lines changed

9 files changed

+60
-95
lines changed

compiler/rustc_infer/src/traits/mod.rs

+10
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ mod project;
88
mod structural_impls;
99
pub mod util;
1010

11+
use std::cmp;
12+
1113
use hir::def_id::LocalDefId;
1214
use rustc_hir as hir;
1315
use rustc_middle::ty::error::{ExpectedFound, TypeError};
@@ -139,6 +141,14 @@ impl<'tcx, O> Obligation<'tcx, O> {
139141
Self::with_depth(tcx, cause, 0, param_env, predicate)
140142
}
141143

144+
/// We often create nested obligations without setting the correct depth.
145+
///
146+
/// To deal with this evaluate and fulfill explicitly update the depth
147+
/// of nested obligations using this function.
148+
pub fn set_depth_from_parent(&mut self, parent_depth: usize) {
149+
self.recursion_depth = cmp::max(parent_depth + 1, self.recursion_depth);
150+
}
151+
142152
pub fn with_depth(
143153
tcx: TyCtxt<'tcx>,
144154
cause: ObligationCause<'tcx>,

compiler/rustc_trait_selection/src/traits/select/mod.rs

+19-52
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
595595
self.evaluate_predicates_recursively_in_new_solver(predicates)
596596
} else {
597597
let mut result = EvaluatedToOk;
598-
for obligation in predicates {
598+
for mut obligation in predicates {
599+
obligation.set_depth_from_parent(stack.depth());
599600
let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?;
600601
if let EvaluatedToErr = eval {
601602
// fast-path - EvaluatedToErr is the top of the lattice,
@@ -661,12 +662,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
661662
let p = bound_predicate.rebind(p);
662663
// Does this code ever run?
663664
match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) {
664-
Ok(Ok(InferOk { mut obligations, .. })) => {
665-
self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
666-
self.evaluate_predicates_recursively(
667-
previous_stack,
668-
obligations.into_iter(),
669-
)
665+
Ok(Ok(InferOk { obligations, .. })) => {
666+
self.evaluate_predicates_recursively(previous_stack, obligations)
670667
}
671668
Ok(Err(_)) => Ok(EvaluatedToErr),
672669
Err(..) => Ok(EvaluatedToAmbig),
@@ -677,12 +674,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
677674
let p = bound_predicate.rebind(p);
678675
// Does this code ever run?
679676
match self.infcx.coerce_predicate(&obligation.cause, obligation.param_env, p) {
680-
Ok(Ok(InferOk { mut obligations, .. })) => {
681-
self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
682-
self.evaluate_predicates_recursively(
683-
previous_stack,
684-
obligations.into_iter(),
685-
)
677+
Ok(Ok(InferOk { obligations, .. })) => {
678+
self.evaluate_predicates_recursively(previous_stack, obligations)
686679
}
687680
Ok(Err(_)) => Ok(EvaluatedToErr),
688681
Err(..) => Ok(EvaluatedToAmbig),
@@ -755,9 +748,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
755748
arg,
756749
obligation.cause.span,
757750
) {
758-
Some(mut obligations) => {
759-
self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
760-
751+
Some(obligations) => {
761752
cache.wf_args.borrow_mut().push((arg, previous_stack.depth()));
762753
let result =
763754
self.evaluate_predicates_recursively(previous_stack, obligations);
@@ -826,10 +817,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
826817
}
827818
}
828819

829-
self.add_depth(
830-
subobligations.iter_mut(),
831-
obligation.recursion_depth,
832-
);
820+
// Need to explicitly set the depth of nested goals here as
821+
// projection obligations can cycle by themselves and in
822+
// `evaluate_predicates_recursively` we only add the depth
823+
// for parent trait goals because only these get added to the
824+
// `TraitObligationStackList`.
825+
for subobligation in subobligations.iter_mut() {
826+
subobligation.set_depth_from_parent(obligation.recursion_depth);
827+
}
833828
let res = self.evaluate_predicates_recursively(
834829
previous_stack,
835830
subobligations,
@@ -909,38 +904,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
909904
if a.def.did == b.def.did
910905
&& tcx.def_kind(a.def.did) == DefKind::AssocConst =>
911906
{
912-
if let Ok(new_obligations) = self
907+
if let Ok(InferOk { obligations, value: () }) = self
913908
.infcx
914909
.at(&obligation.cause, obligation.param_env)
915910
.trace(c1, c2)
916911
.eq(DefineOpaqueTypes::No, a.substs, b.substs)
917912
{
918-
let mut obligations = new_obligations.obligations;
919-
self.add_depth(
920-
obligations.iter_mut(),
921-
obligation.recursion_depth,
922-
);
923913
return self.evaluate_predicates_recursively(
924914
previous_stack,
925-
obligations.into_iter(),
915+
obligations,
926916
);
927917
}
928918
}
929919
(_, Unevaluated(_)) | (Unevaluated(_), _) => (),
930920
(_, _) => {
931-
if let Ok(new_obligations) = self
921+
if let Ok(InferOk { obligations, value: () }) = self
932922
.infcx
933923
.at(&obligation.cause, obligation.param_env)
934924
.eq(DefineOpaqueTypes::No, c1, c2)
935925
{
936-
let mut obligations = new_obligations.obligations;
937-
self.add_depth(
938-
obligations.iter_mut(),
939-
obligation.recursion_depth,
940-
);
941926
return self.evaluate_predicates_recursively(
942927
previous_stack,
943-
obligations.into_iter(),
928+
obligations,
944929
);
945930
}
946931
}
@@ -1366,24 +1351,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
13661351
self.infcx.evaluation_cache.insert((param_env, trait_pred), dep_node, result);
13671352
}
13681353

1369-
/// For various reasons, it's possible for a subobligation
1370-
/// to have a *lower* recursion_depth than the obligation used to create it.
1371-
/// Projection sub-obligations may be returned from the projection cache,
1372-
/// which results in obligations with an 'old' `recursion_depth`.
1373-
/// Additionally, methods like `InferCtxt.subtype_predicate` produce
1374-
/// subobligations without taking in a 'parent' depth, causing the
1375-
/// generated subobligations to have a `recursion_depth` of `0`.
1376-
///
1377-
/// To ensure that obligation_depth never decreases, we force all subobligations
1378-
/// to have at least the depth of the original obligation.
1379-
fn add_depth<T: 'cx, I: Iterator<Item = &'cx mut Obligation<'tcx, T>>>(
1380-
&self,
1381-
it: I,
1382-
min_depth: usize,
1383-
) {
1384-
it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1);
1385-
}
1386-
13871354
fn check_recursion_depth<T>(
13881355
&self,
13891356
depth: usize,

tests/ui/associated-consts/issue-93775.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
// Regression for #93775, needs build-pass to test it.
55

6-
#![recursion_limit = "1000"]
6+
#![recursion_limit = "1001"]
77

88
use std::marker::PhantomData;
99

tests/ui/did_you_mean/recursion_limit.stderr

+1-6
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
1-
error[E0275]: overflow evaluating the requirement `K: Send`
1+
error[E0275]: overflow evaluating the requirement `J: Send`
22
--> $DIR/recursion_limit.rs:34:5
33
|
44
LL | is_send::<A>();
55
| ^^^^^^^^^^^^
66
|
77
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`recursion_limit`)
8-
note: required because it appears within the type `J`
9-
--> $DIR/recursion_limit.rs:24:9
10-
|
11-
LL | link! { J, K }
12-
| ^
138
note: required because it appears within the type `I`
149
--> $DIR/recursion_limit.rs:23:9
1510
|

tests/ui/error-codes/E0275.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ note: required for `Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<Bar<
1111
LL | impl<T> Foo for T where Bar<T>: Foo {}
1212
| ^^^ ^ --- unsatisfied trait bound introduced here
1313
= note: the full type name has been written to '$TEST_BUILD_DIR/error-codes/E0275/E0275.long-type-hash.txt'
14-
= note: 127 redundant requirements hidden
14+
= note: 126 redundant requirements hidden
1515
= note: required for `Bar<T>` to implement `Foo`
1616

1717
error: aborting due to previous error

tests/ui/issues/issue-20413.stderr

+17-17
Original file line numberDiff line numberDiff line change
@@ -20,51 +20,51 @@ note: required for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoDa
2020
LL | impl<T> Foo for T where NoData<T>: Foo {
2121
| ^^^ ^ --- unsatisfied trait bound introduced here
2222
= note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt'
23-
= note: 127 redundant requirements hidden
23+
= note: 126 redundant requirements hidden
2424
= note: required for `NoData<T>` to implement `Foo`
2525

26-
error[E0275]: overflow evaluating the requirement `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<...>>>>>>>: Baz`
26+
error[E0275]: overflow evaluating the requirement `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<...>>>>>>>: Bar`
2727
--> $DIR/issue-20413.rs:28:42
2828
|
2929
LL | impl<T> Bar for T where EvenLessData<T>: Baz {
3030
| ^^^
3131
|
3232
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`)
33-
note: required for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<...>>>>>>>` to implement `Bar`
34-
--> $DIR/issue-20413.rs:28:9
35-
|
36-
LL | impl<T> Bar for T where EvenLessData<T>: Baz {
37-
| ^^^ ^ --- unsatisfied trait bound introduced here
38-
= note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt'
3933
note: required for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<...>>>>>>>` to implement `Baz`
4034
--> $DIR/issue-20413.rs:35:9
4135
|
4236
LL | impl<T> Baz for T where AlmostNoData<T>: Bar {
4337
| ^^^ ^ --- unsatisfied trait bound introduced here
4438
= note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt'
45-
= note: 126 redundant requirements hidden
39+
note: required for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<...>>>>>>>` to implement `Bar`
40+
--> $DIR/issue-20413.rs:28:9
41+
|
42+
LL | impl<T> Bar for T where EvenLessData<T>: Baz {
43+
| ^^^ ^ --- unsatisfied trait bound introduced here
44+
= note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt'
45+
= note: 125 redundant requirements hidden
4646
= note: required for `EvenLessData<T>` to implement `Baz`
4747

48-
error[E0275]: overflow evaluating the requirement `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<...>>>>>>>: Bar`
48+
error[E0275]: overflow evaluating the requirement `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<...>>>>>>>: Baz`
4949
--> $DIR/issue-20413.rs:35:42
5050
|
5151
LL | impl<T> Baz for T where AlmostNoData<T>: Bar {
5252
| ^^^
5353
|
5454
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_20413`)
55-
note: required for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<...>>>>>>>` to implement `Baz`
56-
--> $DIR/issue-20413.rs:35:9
57-
|
58-
LL | impl<T> Baz for T where AlmostNoData<T>: Bar {
59-
| ^^^ ^ --- unsatisfied trait bound introduced here
60-
= note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt'
6155
note: required for `AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<...>>>>>>>` to implement `Bar`
6256
--> $DIR/issue-20413.rs:28:9
6357
|
6458
LL | impl<T> Bar for T where EvenLessData<T>: Baz {
6559
| ^^^ ^ --- unsatisfied trait bound introduced here
6660
= note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt'
67-
= note: 126 redundant requirements hidden
61+
note: required for `EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<AlmostNoData<EvenLessData<...>>>>>>>` to implement `Baz`
62+
--> $DIR/issue-20413.rs:35:9
63+
|
64+
LL | impl<T> Baz for T where AlmostNoData<T>: Bar {
65+
| ^^^ ^ --- unsatisfied trait bound introduced here
66+
= note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-20413/issue-20413.long-type-hash.txt'
67+
= note: 125 redundant requirements hidden
6868
= note: required for `AlmostNoData<T>` to implement `Bar`
6969

7070
error: aborting due to 4 previous errors

tests/ui/traits/cycle-cache-err-60010.stderr

+1-14
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,9 @@
1-
error[E0275]: overflow evaluating the requirement `SalsaStorage: RefUnwindSafe`
1+
error[E0275]: overflow evaluating the requirement `RootDatabase: RefUnwindSafe`
22
--> $DIR/cycle-cache-err-60010.rs:27:13
33
|
44
LL | _parse: <ParseQuery as Query<RootDatabase>>::Data,
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
7-
= note: required because it appears within the type `PhantomData<SalsaStorage>`
8-
= note: required because it appears within the type `Unique<SalsaStorage>`
9-
= note: required because it appears within the type `Box<SalsaStorage>`
10-
note: required because it appears within the type `Runtime<RootDatabase>`
11-
--> $DIR/cycle-cache-err-60010.rs:23:8
12-
|
13-
LL | struct Runtime<DB: Database> {
14-
| ^^^^^^^
15-
note: required because it appears within the type `RootDatabase`
16-
--> $DIR/cycle-cache-err-60010.rs:20:8
17-
|
18-
LL | struct RootDatabase {
19-
| ^^^^^^^^^^^^
207
note: required for `RootDatabase` to implement `SourceDatabase`
218
--> $DIR/cycle-cache-err-60010.rs:44:9
229
|

tests/ui/traits/issue-91949-hangs-on-recursion.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// build-fail
22
// compile-flags: -Zinline-mir=no
3-
// error-pattern: overflow evaluating the requirement `(): Sized`
3+
// error-pattern: overflow evaluating the requirement `<std::iter::Empty<()> as Iterator>::Item == ()`
44
// error-pattern: function cannot return without recursing
55
// normalize-stderr-test: "long-type-\d+" -> "long-type-hash"
66

tests/ui/traits/issue-91949-hangs-on-recursion.stderr

+9-3
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,17 @@ LL | recurse(IteratorOfWrapped(elements).map(|t| t.0))
1212
= help: a `loop` may express intention better if this is on purpose
1313
= note: `#[warn(unconditional_recursion)]` on by default
1414

15-
error[E0275]: overflow evaluating the requirement `(): Sized`
15+
error[E0275]: overflow evaluating the requirement `<std::iter::Empty<()> as Iterator>::Item == ()`
1616
|
1717
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "512"]` attribute to your crate (`issue_91949_hangs_on_recursion`)
18-
= note: required for `std::iter::Empty<()>` to implement `Iterator`
19-
= note: 171 redundant requirements hidden
18+
note: required for `IteratorOfWrapped<(), std::iter::Empty<()>>` to implement `Iterator`
19+
--> $DIR/issue-91949-hangs-on-recursion.rs:16:32
20+
|
21+
LL | impl<T, I: Iterator<Item = T>> Iterator for IteratorOfWrapped<T, I> {
22+
| -------- ^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
23+
| |
24+
| unsatisfied trait bound introduced here
25+
= note: 256 redundant requirements hidden
2026
= note: required for `IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<..., ...>>, ...>>, ...>>` to implement `Iterator`
2127
= note: the full type name has been written to '$TEST_BUILD_DIR/traits/issue-91949-hangs-on-recursion/issue-91949-hangs-on-recursion.long-type-hash.txt'
2228

0 commit comments

Comments
 (0)