Skip to content

Commit a62ecba

Browse files
Detect cyclic subtype goals in new solver
1 parent e7271f4 commit a62ecba

File tree

9 files changed

+99
-21
lines changed

9 files changed

+99
-21
lines changed

compiler/rustc_infer/src/infer/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ impl<'tcx> InferCtxtInner<'tcx> {
199199
}
200200

201201
#[inline]
202-
fn type_variables(&mut self) -> type_variable::TypeVariableTable<'_, 'tcx> {
202+
pub fn type_variables(&mut self) -> type_variable::TypeVariableTable<'_, 'tcx> {
203203
self.type_variable_storage.with_log(&mut self.undo_log)
204204
}
205205

compiler/rustc_middle/src/traits/solve.rs

+12
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ pub struct ExternalConstraintsData<'tcx> {
125125
// FIXME: implement this.
126126
pub region_constraints: QueryRegionConstraints<'tcx>,
127127
pub opaque_types: Vec<(Ty<'tcx>, Ty<'tcx>)>,
128+
pub stalled_subtypes: Vec<(Ty<'tcx>, Ty<'tcx>)>,
128129
}
129130

130131
// FIXME: Having to clone `region_constraints` for folding feels bad and
@@ -144,13 +145,23 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ExternalConstraints<'tcx> {
144145
.iter()
145146
.map(|opaque| opaque.try_fold_with(folder))
146147
.collect::<Result<_, F::Error>>()?,
148+
stalled_subtypes: self
149+
.stalled_subtypes
150+
.iter()
151+
.map(|subtype| subtype.try_fold_with(folder))
152+
.collect::<Result<_, F::Error>>()?,
147153
}))
148154
}
149155

150156
fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
151157
TypeFolder::interner(folder).mk_external_constraints(ExternalConstraintsData {
152158
region_constraints: self.region_constraints.clone().fold_with(folder),
153159
opaque_types: self.opaque_types.iter().map(|opaque| opaque.fold_with(folder)).collect(),
160+
stalled_subtypes: self
161+
.stalled_subtypes
162+
.iter()
163+
.map(|subtype| subtype.fold_with(folder))
164+
.collect(),
154165
})
155166
}
156167
}
@@ -162,6 +173,7 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ExternalConstraints<'tcx> {
162173
) -> std::ops::ControlFlow<V::BreakTy> {
163174
self.region_constraints.visit_with(visitor)?;
164175
self.opaque_types.visit_with(visitor)?;
176+
self.stalled_subtypes.visit_with(visitor)?;
165177
ControlFlow::Continue(())
166178
}
167179
}

compiler/rustc_trait_selection/src/solve/eval_ctxt.rs

+8
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ pub struct EvalCtxt<'a, 'tcx> {
5757
pub(super) search_graph: &'a mut SearchGraph<'tcx>,
5858

5959
pub(super) nested_goals: NestedGoals<'tcx>,
60+
61+
// Subtyping predicates which have stalled. These are passed down in query
62+
// responses to help detect cycle errors in cases where we're computing a
63+
// goal like `?0 <: Box<?1>` when we already know that `?0 <: ?1`.
64+
pub(super) stalled_subtypes: Vec<(Ty<'tcx>, Ty<'tcx>)>,
6065
}
6166

6267
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -121,6 +126,7 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
121126
max_input_universe: ty::UniverseIndex::ROOT,
122127
var_values: CanonicalVarValues::dummy(),
123128
nested_goals: NestedGoals::new(),
129+
stalled_subtypes: vec![],
124130
};
125131
let result = ecx.evaluate_goal(IsNormalizesToHack::No, goal);
126132

@@ -172,6 +178,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
172178
max_input_universe: canonical_goal.max_universe,
173179
search_graph,
174180
nested_goals: NestedGoals::new(),
181+
stalled_subtypes: vec![],
175182
};
176183
ecx.compute_goal(goal)
177184
})
@@ -404,6 +411,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
404411
max_input_universe: self.max_input_universe,
405412
search_graph: self.search_graph,
406413
nested_goals: self.nested_goals.clone(),
414+
stalled_subtypes: self.stalled_subtypes.clone(),
407415
};
408416
self.infcx.probe(|_| f(&mut ecx))
409417
}

compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs

+24-7
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use rustc_infer::infer::canonical::CanonicalVarValues;
1616
use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints};
1717
use rustc_middle::traits::query::NoSolution;
1818
use rustc_middle::traits::solve::{ExternalConstraints, ExternalConstraintsData};
19-
use rustc_middle::ty::{self, GenericArgKind};
19+
use rustc_middle::ty::{self, GenericArgKind, Ty};
2020
use rustc_span::DUMMY_SP;
2121
use std::iter;
2222
use std::ops::Deref;
@@ -79,9 +79,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
7979
)
8080
});
8181
let opaque_types = self.infcx.clone_opaque_types_for_query_response();
82-
Ok(self
83-
.tcx()
84-
.mk_external_constraints(ExternalConstraintsData { region_constraints, opaque_types }))
82+
Ok(self.tcx().mk_external_constraints(ExternalConstraintsData {
83+
region_constraints,
84+
opaque_types,
85+
stalled_subtypes: self.stalled_subtypes.clone(),
86+
}))
8587
}
8688

8789
/// After calling a canonical query, we apply the constraints returned
@@ -102,12 +104,17 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
102104
let Response { var_values, external_constraints, certainty } =
103105
response.substitute(self.tcx(), &substitution);
104106

105-
let nested_goals = self.unify_query_var_values(param_env, &original_values, var_values)?;
106-
107107
// FIXME: implement external constraints.
108-
let ExternalConstraintsData { region_constraints, opaque_types: _ } =
108+
let ExternalConstraintsData { region_constraints, stalled_subtypes, opaque_types: _ } =
109109
external_constraints.deref();
110110
self.register_region_constraints(region_constraints);
111+
assert!(
112+
stalled_subtypes.is_empty() || certainty != Certainty::Yes,
113+
"stalled_subtypes is non-empty: {stalled_subtypes:?}, but certainty is Yes"
114+
);
115+
self.register_stalled_subtypes(stalled_subtypes);
116+
117+
let nested_goals = self.unify_query_var_values(param_env, &original_values, var_values)?;
111118

112119
Ok((certainty, nested_goals))
113120
}
@@ -227,4 +234,14 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
227234
let _ = member_constraint;
228235
}
229236
}
237+
238+
fn register_stalled_subtypes(&mut self, stalled_subtypes: &[(Ty<'tcx>, Ty<'tcx>)]) {
239+
for (sub, sup) in stalled_subtypes {
240+
if let ty::Infer(ty::TyVar(sub_vid)) = *self.infcx.shallow_resolve(*sub).kind()
241+
&& let ty::Infer(ty::TyVar(sup_vid)) = *self.infcx.shallow_resolve(*sup).kind()
242+
{
243+
self.infcx.inner.borrow_mut().type_variables().sub(sub_vid, sup_vid);
244+
}
245+
}
246+
}
230247
}

compiler/rustc_trait_selection/src/solve/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
105105
goal: Goal<'tcx, SubtypePredicate<'tcx>>,
106106
) -> QueryResult<'tcx> {
107107
if goal.predicate.a.is_ty_var() && goal.predicate.b.is_ty_var() {
108+
self.stalled_subtypes.push((goal.predicate.a, goal.predicate.b));
108109
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
109110
} else {
110111
self.sub(goal.param_env, goal.predicate.a, goal.predicate.b)?;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// compile-flags: -Ztrait-solver=next
2+
3+
fn main() {
4+
let x;
5+
x = Box::new(x);
6+
//~^ ERROR mismatched types
7+
//~| NOTE cyclic type of infinite size
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/cyclic-type.rs:5:9
3+
|
4+
LL | x = Box::new(x);
5+
| ^^^^^^^^^^^ cyclic type of infinite size
6+
|
7+
help: consider unboxing the value
8+
|
9+
LL | x = *Box::new(x);
10+
| +
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0308`.
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,32 @@
1-
error[E0308]: mismatched types
2-
--> $DIR/equating-projection-cyclically.rs:22:19
1+
error[E0055]: reached the recursion limit while auto-dereferencing `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<_ as Test>::Assoc as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target`
2+
|
3+
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`equating_projection_cyclically`)
4+
5+
error[E0055]: reached the recursion limit while auto-dereferencing `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<_ as Test>::Assoc as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target`
6+
--> $DIR/equating-projection-cyclically.rs:22:9
37
|
48
LL | x = transform(x);
5-
| ^ expected inferred type, found associated type
9+
| ^^^^^^^^^^^^ deref recursion limit reached
610
|
7-
= note: expected type `_`
8-
found associated type `<_ as Test>::Assoc`
9-
= help: consider constraining the associated type `<_ as Test>::Assoc` to `_`
10-
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
11+
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`equating_projection_cyclically`)
12+
13+
error[E0055]: reached the recursion limit while auto-dereferencing `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<_ as Test>::Assoc as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target as Deref>::Target`
14+
--> $DIR/equating-projection-cyclically.rs:22:9
15+
|
16+
LL | x = transform(x);
17+
| ^^^^^^^^^^^^ deref recursion limit reached
18+
|
19+
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`equating_projection_cyclically`)
20+
21+
error[E0308]: mismatched types
22+
--> $DIR/equating-projection-cyclically.rs:22:9
23+
|
24+
LL | x = transform(x);
25+
| ^^^^^^^^^^^^- help: try using a conversion method: `.to_string()`
26+
| |
27+
| cyclic type of infinite size
1128

12-
error: aborting due to previous error
29+
error: aborting due to 4 previous errors
1330

14-
For more information about this error, try `rustc --explain E0308`.
31+
Some errors have detailed explanations: E0055, E0308.
32+
For more information about an error, try `rustc --explain E0055`.

tests/ui/traits/new-solver/normalizes_to_ignores_unnormalizable_candidate.self_infer.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
error[E0282]: type annotations needed
2-
--> $DIR/normalizes_to_ignores_unnormalizable_candidate.rs:36:5
2+
--> $DIR/normalizes_to_ignores_unnormalizable_candidate.rs:36:9
33
|
44
LL | foo(unconstrained())
5-
| ^^^ cannot infer type of the type parameter `T` declared on the function `foo`
5+
| ^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `unconstrained`
66
|
77
help: consider specifying the generic argument
88
|
9-
LL | foo::<T>(unconstrained())
10-
| +++++
9+
LL | foo(unconstrained::<T>())
10+
| +++++
1111

1212
error: aborting due to previous error
1313

0 commit comments

Comments
 (0)