Skip to content

Commit 7f22e9c

Browse files
committed
eagerly normalize when adding goals
1 parent 474bee7 commit 7f22e9c

File tree

9 files changed

+190
-18
lines changed

9 files changed

+190
-18
lines changed

compiler/rustc_middle/src/ty/predicate.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -113,17 +113,14 @@ impl<'tcx> Predicate<'tcx> {
113113
#[inline]
114114
pub fn allow_normalization(self) -> bool {
115115
match self.kind().skip_binder() {
116-
PredicateKind::Clause(ClauseKind::WellFormed(_)) => false,
117-
// `NormalizesTo` is only used in the new solver, so this shouldn't
118-
// matter. Normalizing `term` would be 'wrong' however, as it changes whether
119-
// `normalizes-to(<T as Trait>::Assoc, <T as Trait>::Assoc)` holds.
120-
PredicateKind::NormalizesTo(..) => false,
116+
PredicateKind::Clause(ClauseKind::WellFormed(_))
117+
| PredicateKind::AliasRelate(..)
118+
| PredicateKind::NormalizesTo(..) => false,
121119
PredicateKind::Clause(ClauseKind::Trait(_))
122120
| PredicateKind::Clause(ClauseKind::RegionOutlives(_))
123121
| PredicateKind::Clause(ClauseKind::TypeOutlives(_))
124122
| PredicateKind::Clause(ClauseKind::Projection(_))
125123
| PredicateKind::Clause(ClauseKind::ConstArgHasType(..))
126-
| PredicateKind::AliasRelate(..)
127124
| PredicateKind::ObjectSafe(_)
128125
| PredicateKind::Subtype(_)
129126
| PredicateKind::Coerce(_)

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

+11-4
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,6 @@ pub(in crate::solve) fn instantiate_canonical_state<'tcx, T: TypeFoldable<TyCtxt
418418
) -> T {
419419
// In case any fresh inference variables have been created between `state`
420420
// and the previous instantiation, extend `orig_values` for it.
421-
assert!(orig_values.len() <= state.value.var_values.len());
422421
for i in orig_values.len()..state.value.var_values.len() {
423422
let unconstrained = match state.value.var_values.var_values[i].unpack() {
424423
ty::GenericArgKind::Lifetime(_) => {
@@ -431,11 +430,19 @@ pub(in crate::solve) fn instantiate_canonical_state<'tcx, T: TypeFoldable<TyCtxt
431430
orig_values.push(unconstrained);
432431
}
433432

434-
let instantiation =
435-
EvalCtxt::compute_query_response_instantiation_values(infcx, orig_values, &state);
433+
let instantiation = EvalCtxt::compute_query_response_instantiation_values(
434+
infcx,
435+
&orig_values[..state.value.var_values.len()],
436+
&state,
437+
);
436438

437439
let inspect::State { var_values, data } = state.instantiate(infcx.tcx, &instantiation);
438440

439-
EvalCtxt::unify_query_var_values(infcx, param_env, orig_values, var_values);
441+
EvalCtxt::unify_query_var_values(
442+
infcx,
443+
param_env,
444+
&orig_values[..state.value.var_values.len()],
445+
var_values,
446+
);
440447
data
441448
}

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

+49-2
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,15 @@ use rustc_middle::traits::solve::{
1616
inspect, CanonicalInput, CanonicalResponse, Certainty, PredefinedOpaquesData, QueryResult,
1717
};
1818
use rustc_middle::traits::specialization_graph;
19+
use rustc_middle::ty::AliasRelationDirection;
20+
use rustc_middle::ty::TypeFolder;
1921
use rustc_middle::ty::{
2022
self, InferCtxtLike, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
2123
TypeVisitable, TypeVisitableExt, TypeVisitor,
2224
};
2325
use rustc_session::config::DumpSolverProofTree;
2426
use rustc_span::DUMMY_SP;
27+
use rustc_type_ir::fold::TypeSuperFoldable;
2528
use rustc_type_ir::{self as ir, CanonicalVarValues, Interner};
2629
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
2730

@@ -468,13 +471,23 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
468471
}
469472

470473
#[instrument(level = "trace", skip(self))]
471-
pub(super) fn add_normalizes_to_goal(&mut self, goal: Goal<'tcx, ty::NormalizesTo<'tcx>>) {
474+
pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal<'tcx, ty::NormalizesTo<'tcx>>) {
475+
goal.predicate = goal
476+
.predicate
477+
.fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env });
472478
self.inspect.add_normalizes_to_goal(self.infcx, self.max_input_universe, goal);
473479
self.nested_goals.normalizes_to_goals.push(goal);
474480
}
475481

476482
#[instrument(level = "debug", skip(self))]
477-
pub(super) fn add_goal(&mut self, source: GoalSource, goal: Goal<'tcx, ty::Predicate<'tcx>>) {
483+
pub(super) fn add_goal(
484+
&mut self,
485+
source: GoalSource,
486+
mut goal: Goal<'tcx, ty::Predicate<'tcx>>,
487+
) {
488+
goal.predicate = goal
489+
.predicate
490+
.fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env });
478491
self.inspect.add_goal(self.infcx, self.max_input_universe, source, goal);
479492
self.nested_goals.goals.push((source, goal));
480493
}
@@ -1101,3 +1114,37 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
11011114
});
11021115
}
11031116
}
1117+
1118+
struct ReplaceAliasWithInfer<'me, 'a, 'tcx> {
1119+
ecx: &'me mut EvalCtxt<'a, InferCtxt<'tcx>>,
1120+
param_env: ty::ParamEnv<'tcx>,
1121+
}
1122+
1123+
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceAliasWithInfer<'_, '_, 'tcx> {
1124+
fn interner(&self) -> TyCtxt<'tcx> {
1125+
self.ecx.tcx()
1126+
}
1127+
1128+
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
1129+
match *ty.kind() {
1130+
ty::Alias(..) if !ty.has_escaping_bound_vars() => {
1131+
let infer_ty = self.ecx.next_ty_infer();
1132+
let normalizes_to = ty::PredicateKind::AliasRelate(
1133+
ty.into(),
1134+
infer_ty.into(),
1135+
AliasRelationDirection::Equate,
1136+
);
1137+
self.ecx.add_goal(
1138+
GoalSource::Misc,
1139+
Goal::new(self.interner(), self.param_env, normalizes_to),
1140+
);
1141+
infer_ty
1142+
}
1143+
_ => ty.super_fold_with(self),
1144+
}
1145+
}
1146+
1147+
fn fold_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
1148+
if predicate.allow_normalization() { predicate.super_fold_with(self) } else { predicate }
1149+
}
1150+
}

tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.next.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ LL | impl<T> Trait for Box<T> {}
1212
| ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<_>`
1313
|
1414
= note: downstream crates may implement trait `WithAssoc<'a>` for type `std::boxed::Box<_>`
15-
= note: downstream crates may implement trait `WhereBound` for type `std::boxed::Box<<std::boxed::Box<_> as WithAssoc<'a>>::Assoc>`
15+
= note: downstream crates may implement trait `WhereBound` for type `std::boxed::Box<_>`
1616

1717
error: aborting due to 1 previous error
1818

tests/ui/coherence/occurs-check/opaques.next.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ error[E0282]: type annotations needed
1111
--> $DIR/opaques.rs:13:20
1212
|
1313
LL | pub fn cast<T>(x: Container<Alias<T>, T>) -> Container<T, T> {
14-
| ^ cannot infer type for associated type `<T as Trait<T>>::Assoc`
14+
| ^ cannot infer type
1515

1616
error: aborting due to 2 previous errors
1717

tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr

+18-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,22 @@ LL | where
1616
LL | T: AsExpression<Self::SqlType>,
1717
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::check`
1818

19-
error: aborting due to 1 previous error
19+
error[E0277]: the trait bound `&str: AsExpression<Integer>` is not satisfied
20+
--> $DIR/as_expression.rs:57:15
21+
|
22+
LL | SelectInt.check("bar");
23+
| ^^^^^ the trait `AsExpression<Integer>` is not implemented for `&str`
24+
|
25+
= help: the trait `AsExpression<Text>` is implemented for `&str`
26+
= help: for that trait implementation, expected `Text`, found `Integer`
27+
28+
error[E0271]: type mismatch resolving `<&str as AsExpression<<SelectInt as Expression>::SqlType>>::Expression == _`
29+
--> $DIR/as_expression.rs:57:5
30+
|
31+
LL | SelectInt.check("bar");
32+
| ^^^^^^^^^^^^^^^^^^^^^^ types differ
33+
34+
error: aborting due to 3 previous errors
2035

21-
For more information about this error, try `rustc --explain E0277`.
36+
Some errors have detailed explanations: E0271, E0277.
37+
For more information about an error, try `rustc --explain E0271`.

tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ impl<T> Foo for T where T: Expression {}
5555

5656
fn main() {
5757
SelectInt.check("bar");
58-
//[next]~^ ERROR the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
59-
//[current]~^^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
58+
//~^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
59+
//[next]~| the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
60+
//[next]~| type mismatch
6061
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
//@ compile-flags: -Znext-solver
2+
3+
// A regression test for #125269. We previously ended up
4+
// recursively proving `&<_ as SpeciesPackedElem>::Assoc: Typed`
5+
// for all aliases which ended up causing exponential blowup.
6+
//
7+
// This has been fixed by eagerly normalizing the associated
8+
// type before computing the nested goals, resulting in an
9+
// immediate inductive cycle.
10+
11+
pub trait Typed {}
12+
13+
pub struct SpeciesCases<E>(E);
14+
15+
pub trait SpeciesPackedElim {
16+
type Ogre;
17+
type Cyclops;
18+
type Wendigo;
19+
type Cavetroll;
20+
type Mountaintroll;
21+
type Swamptroll;
22+
type Dullahan;
23+
type Werewolf;
24+
type Occultsaurok;
25+
type Mightysaurok;
26+
type Slysaurok;
27+
type Mindflayer;
28+
type Minotaur;
29+
type Tidalwarrior;
30+
type Yeti;
31+
type Harvester;
32+
type Blueoni;
33+
type Redoni;
34+
type Cultistwarlord;
35+
type Cultistwarlock;
36+
type Huskbrute;
37+
type Tursus;
38+
type Gigasfrost;
39+
type AdletElder;
40+
type SeaBishop;
41+
type HaniwaGeneral;
42+
type TerracottaBesieger;
43+
type TerracottaDemolisher;
44+
type TerracottaPunisher;
45+
type TerracottaPursuer;
46+
type Cursekeeper;
47+
}
48+
49+
impl<'b, E: SpeciesPackedElim> Typed for &'b SpeciesCases<E>
50+
where
51+
&'b E::Ogre: Typed,
52+
&'b E::Cyclops: Typed,
53+
&'b E::Wendigo: Typed,
54+
&'b E::Cavetroll: Typed,
55+
&'b E::Mountaintroll: Typed,
56+
&'b E::Swamptroll: Typed,
57+
&'b E::Dullahan: Typed,
58+
&'b E::Werewolf: Typed,
59+
&'b E::Occultsaurok: Typed,
60+
&'b E::Mightysaurok: Typed,
61+
&'b E::Slysaurok: Typed,
62+
&'b E::Mindflayer: Typed,
63+
&'b E::Minotaur: Typed,
64+
&'b E::Tidalwarrior: Typed,
65+
&'b E::Yeti: Typed,
66+
&'b E::Harvester: Typed,
67+
&'b E::Blueoni: Typed,
68+
&'b E::Redoni: Typed,
69+
&'b E::Cultistwarlord: Typed,
70+
&'b E::Cultistwarlock: Typed,
71+
&'b E::Huskbrute: Typed,
72+
&'b E::Tursus: Typed,
73+
&'b E::Gigasfrost: Typed,
74+
&'b E::AdletElder: Typed,
75+
&'b E::SeaBishop: Typed,
76+
&'b E::HaniwaGeneral: Typed,
77+
&'b E::TerracottaBesieger: Typed,
78+
&'b E::TerracottaDemolisher: Typed,
79+
&'b E::TerracottaPunisher: Typed,
80+
&'b E::TerracottaPursuer: Typed,
81+
&'b E::Cursekeeper: Typed,
82+
{}
83+
84+
fn foo<T: Typed>() {}
85+
86+
fn main() {
87+
foo::<&_>();
88+
//~^ ERROR overflow evaluating the requirement `&_: Typed`
89+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0275]: overflow evaluating the requirement `&_: Typed`
2+
--> $DIR/cycle-modulo-ambig-aliases.rs:87:11
3+
|
4+
LL | foo::<&_>();
5+
| ^^
6+
|
7+
note: required by a bound in `foo`
8+
--> $DIR/cycle-modulo-ambig-aliases.rs:84:11
9+
|
10+
LL | fn foo<T: Typed>() {}
11+
| ^^^^^ required by this bound in `foo`
12+
13+
error: aborting due to 1 previous error
14+
15+
For more information about this error, try `rustc --explain E0275`.

0 commit comments

Comments
 (0)