Skip to content

Commit a2abacc

Browse files
committed
Auto merge of #154433 - ShoyuVanilla:trivialize-normalizes-to, r=<try>
`-Znext-solver` Remove special handling of `NormalizesTo` goal
2 parents e6b64a2 + eea8bac commit a2abacc

File tree

41 files changed

+322
-407
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+322
-407
lines changed

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

Lines changed: 37 additions & 243 deletions
Large diffs are not rendered by default.

compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
use std::marker::PhantomData;
22

3+
use rustc_type_ir::inherent::*;
34
use rustc_type_ir::search_graph::CandidateHeadUsages;
4-
use rustc_type_ir::{InferCtxtLike, Interner};
5+
use rustc_type_ir::solve::{Certainty, Goal};
6+
use rustc_type_ir::{self as ty, InferCtxtLike, Interner};
57
use tracing::instrument;
68

9+
use crate::canonical::instantiate_and_apply_query_response;
710
use crate::delegate::SolverDelegate;
811
use crate::solve::assembly::Candidate;
12+
use crate::solve::eval_ctxt::CurrentGoalKind;
913
use crate::solve::{
1014
BuiltinImplSource, CandidateSource, EvalCtxt, NoSolution, QueryResult, inspect,
1115
};
@@ -135,4 +139,54 @@ where
135139
source,
136140
}
137141
}
142+
143+
/// When probing candidates for the `NormalizesTo` goal, the projection term should be
144+
/// fully unconstrained. This helps it by replacing the projection term to an unconstrained
145+
/// inference var, probe with `CurrentGoalKind::NormalizesTo` to handle ambiguous nested
146+
/// goals, instantiate and apply the response and then add those nested goals to the root
147+
/// context.
148+
pub(in crate::solve) fn probe_with_unconstrained_projection_term(
149+
&mut self,
150+
goal: Goal<I, ty::NormalizesTo<I>>,
151+
f: impl FnOnce(&mut EvalCtxt<'_, D, I>, Goal<I, ty::NormalizesTo<I>>) -> QueryResult<I>,
152+
) -> Result<(I::Term, Certainty), NoSolution> {
153+
let cx = self.cx();
154+
let unconstrained_term = self.next_term_infer_of_kind(goal.predicate.term);
155+
let unconstrained_goal = goal
156+
.with(cx, ty::NormalizesTo { alias: goal.predicate.alias, term: unconstrained_term });
157+
let extended_var_values = cx.mk_args_from_iter(
158+
self.var_values.var_values.iter().chain(std::iter::once(unconstrained_term.into())),
159+
);
160+
let mut extended_var_kinds = self.var_kinds.to_vec();
161+
let extra_var_kind = match unconstrained_term.kind() {
162+
ty::TermKind::Ty(_) => ty::CanonicalVarKind::Ty {
163+
ui: self.max_input_universe,
164+
sub_root: ty::BoundVar::from_usize(extended_var_kinds.len()),
165+
},
166+
ty::TermKind::Const(_) => ty::CanonicalVarKind::Const(self.max_input_universe),
167+
};
168+
extended_var_kinds.push(extra_var_kind);
169+
let extended_var_kinds = cx.mk_canonical_var_kinds(&extended_var_kinds);
170+
171+
let resp = self.probe(|_| inspect::ProbeKind::ShadowedEnvProbing).enter(|ecx| {
172+
ecx.current_goal_kind = CurrentGoalKind::NormalizesTo;
173+
ecx.var_values.var_values = extended_var_values;
174+
ecx.var_kinds = extended_var_kinds;
175+
f(ecx, unconstrained_goal)
176+
})?;
177+
178+
let (nested_goals, certainty) = instantiate_and_apply_query_response(
179+
self.delegate,
180+
goal.param_env,
181+
extended_var_values.as_slice(),
182+
resp,
183+
self.origin_span,
184+
);
185+
186+
for (source, nested_goal) in nested_goals.0 {
187+
self.add_goal(source, nested_goal);
188+
}
189+
190+
Ok((unconstrained_term, certainty))
191+
}
138192
}

compiler/rustc_next_trait_solver/src/solve/mod.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -344,20 +344,16 @@ where
344344
param_env: I::ParamEnv,
345345
term: I::Term,
346346
) -> Result<I::Term, NoSolution> {
347-
if let Some(_) = term.to_alias_term() {
347+
if let Some(alias) = term.to_alias_term() {
348348
let normalized_term = self.next_term_infer_of_kind(term);
349-
let alias_relate_goal = Goal::new(
349+
let normalizes_to_goal = Goal::new(
350350
self.cx(),
351351
param_env,
352-
ty::PredicateKind::AliasRelate(
353-
term,
354-
normalized_term,
355-
ty::AliasRelationDirection::Equate,
356-
),
352+
ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term: normalized_term }),
357353
);
358354
// We normalize the self type to be able to relate it with
359355
// types from candidates.
360-
self.add_goal(GoalSource::TypeRelating, alias_relate_goal);
356+
self.add_goal(GoalSource::TypeRelating, normalizes_to_goal);
361357
self.try_evaluate_added_goals()?;
362358
Ok(self.resolve_vars_if_possible(normalized_term))
363359
} else {

compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ where
3232
goal.predicate.alias.args,
3333
),
3434
) {
35-
self.instantiate_normalizes_to_term(goal, normalized_const.into());
35+
self.eq(goal.param_env, goal.predicate.term, normalized_const.into())?;
3636
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
3737
} else {
3838
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)

compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ where
3535
cx.const_of_item(free_alias.def_id).instantiate(cx, free_alias.args).into()
3636
};
3737

38-
self.instantiate_normalizes_to_term(goal, actual);
38+
self.eq(goal.param_env, goal.predicate.term, actual)?;
3939
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
4040
}
4141
}

compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ where
5656
} else {
5757
cx.const_of_item(inherent.def_id).instantiate(cx, inherent_args).into()
5858
};
59-
self.instantiate_normalizes_to_term(goal, normalized);
59+
self.eq(goal.param_env, goal.predicate.term, normalized)?;
6060
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
6161
}
6262
}

compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs

Lines changed: 54 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ where
2929
&mut self,
3030
goal: Goal<I, NormalizesTo<I>>,
3131
) -> QueryResult<I> {
32-
debug_assert!(self.term_is_fully_unconstrained(goal));
3332
let cx = self.cx();
3433
match goal.predicate.alias.kind(cx) {
3534
ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => {
@@ -39,49 +38,65 @@ where
3938
let trait_goal: Goal<I, ty::TraitPredicate<I>> = goal.with(cx, trait_ref);
4039
ecx.compute_trait_goal(trait_goal)
4140
})?;
42-
self.assemble_and_merge_candidates(
43-
proven_via,
44-
goal,
45-
|ecx| {
46-
// FIXME(generic_associated_types): Addresses aggressive inference in #92917.
47-
//
48-
// If this type is a GAT with currently unconstrained arguments, we do not
49-
// want to normalize it via a candidate which only applies for a specific
50-
// instantiation. We could otherwise keep the GAT as rigid and succeed this way.
51-
// See tests/ui/generic-associated-types/no-incomplete-gat-arg-inference.rs.
52-
//
53-
// This only avoids normalization if a GAT argument is fully unconstrained.
54-
// This is quite arbitrary but fixing it causes some ambiguity, see #125196.
55-
for arg in goal.predicate.alias.own_args(cx).iter() {
56-
let Some(term) = arg.as_term() else {
57-
continue;
58-
};
59-
match ecx.structurally_normalize_term(goal.param_env, term) {
60-
Ok(term) => {
61-
if term.is_infer() {
62-
return Some(
41+
42+
let (probed_term, certainty) =
43+
self.probe_with_unconstrained_projection_term(goal, |ecx, goal| {
44+
ecx.assemble_and_merge_candidates(
45+
proven_via,
46+
goal,
47+
|ecx| {
48+
// FIXME(generic_associated_types): Addresses aggressive inference in #92917.
49+
//
50+
// If this type is a GAT with currently unconstrained arguments, we do not
51+
// want to normalize it via a candidate which only applies for a specific
52+
// instantiation. We could otherwise keep the GAT as rigid and succeed this way.
53+
// See tests/ui/generic-associated-types/no-incomplete-gat-arg-inference.rs.
54+
//
55+
// This only avoids normalization if a GAT argument is fully unconstrained.
56+
// This is quite arbitrary but fixing it causes some ambiguity, see #125196.
57+
for arg in goal.predicate.alias.own_args(cx).iter() {
58+
let Some(term) = arg.as_term() else {
59+
continue;
60+
};
61+
match ecx.structurally_normalize_term(goal.param_env, term) {
62+
Ok(term) => {
63+
if term.is_infer() {
64+
return Some(
6365
ecx.evaluate_added_goals_and_make_canonical_response(
6466
Certainty::AMBIGUOUS,
6567
),
6668
);
69+
}
70+
}
71+
Err(NoSolution) => return Some(Err(NoSolution)),
6772
}
6873
}
69-
Err(NoSolution) => return Some(Err(NoSolution)),
70-
}
71-
}
7274

73-
None
74-
},
75-
|ecx| {
76-
ecx.probe(|&result| ProbeKind::RigidAlias { result }).enter(|this| {
77-
this.structurally_instantiate_normalizes_to_term(
78-
goal,
79-
goal.predicate.alias,
80-
);
81-
this.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
82-
})
83-
},
84-
)
75+
None
76+
},
77+
|ecx| {
78+
ecx.probe(|&result| ProbeKind::RigidAlias { result }).enter(
79+
|this| {
80+
this.structurally_instantiate_normalizes_to_term(
81+
goal,
82+
goal.predicate.alias,
83+
);
84+
this.evaluate_added_goals_and_make_canonical_response(
85+
Certainty::Yes,
86+
)
87+
},
88+
)
89+
},
90+
)
91+
})?;
92+
93+
self.eq_structurally_relating_aliases(
94+
goal.param_env,
95+
goal.predicate.term,
96+
probed_term,
97+
)?;
98+
99+
self.evaluate_added_goals_and_make_canonical_response(certainty)
85100
}
86101
ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst => {
87102
self.normalize_inherent_associated_term(goal)
@@ -99,18 +114,14 @@ where
99114
/// We know `term` to always be a fully unconstrained inference variable, so
100115
/// `eq` should never fail here. However, in case `term` contains aliases, we
101116
/// emit nested `AliasRelate` goals to structurally normalize the alias.
102-
pub fn instantiate_normalizes_to_term(
103-
&mut self,
104-
goal: Goal<I, NormalizesTo<I>>,
105-
term: I::Term,
106-
) {
117+
fn instantiate_normalizes_to_term(&mut self, goal: Goal<I, NormalizesTo<I>>, term: I::Term) {
107118
self.eq(goal.param_env, goal.predicate.term, term)
108119
.expect("expected goal term to be fully unconstrained");
109120
}
110121

111122
/// Unlike `instantiate_normalizes_to_term` this instantiates the expected term
112123
/// with a rigid alias. Using this is pretty much always wrong.
113-
pub fn structurally_instantiate_normalizes_to_term(
124+
fn structurally_instantiate_normalizes_to_term(
114125
&mut self,
115126
goal: Goal<I, NormalizesTo<I>>,
116127
term: ty::AliasTerm<I>,

compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,12 @@ where
4848
.filter(|&def_id| defining_opaque_types.contains(&def_id))
4949
else {
5050
// If we're not in the defining scope, treat the alias as rigid.
51-
self.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias);
51+
self.relate_rigid_alias_non_alias(
52+
goal.param_env,
53+
goal.predicate.alias,
54+
ty::Invariant,
55+
goal.predicate.term,
56+
)?;
5257
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
5358
};
5459

@@ -111,7 +116,12 @@ where
111116
.as_local()
112117
.filter(|&def_id| defined_opaque_types.contains(&def_id))
113118
else {
114-
self.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias);
119+
self.relate_rigid_alias_non_alias(
120+
goal.param_env,
121+
goal.predicate.alias,
122+
ty::Invariant,
123+
goal.predicate.term,
124+
)?;
115125
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
116126
};
117127

compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -292,13 +292,13 @@ impl<'tcx> BestObligation<'tcx> {
292292
) -> ControlFlow<PredicateObligation<'tcx>> {
293293
assert!(!self.consider_ambiguities);
294294
let tcx = goal.infcx().tcx;
295-
if let ty::Alias(..) = self_ty.kind() {
295+
let term: ty::Term<'tcx> = self_ty.into();
296+
if let Some(alias) = term.to_alias_term() {
296297
let infer_term = goal.infcx().next_ty_var(self.obligation.cause.span);
297-
let pred = ty::PredicateKind::AliasRelate(
298-
self_ty.into(),
299-
infer_term.into(),
300-
ty::AliasRelationDirection::Equate,
301-
);
298+
let pred = ty::PredicateKind::NormalizesTo(ty::NormalizesTo {
299+
alias,
300+
term: infer_term.into(),
301+
});
302302
let obligation =
303303
Obligation::new(tcx, self.obligation.cause.clone(), goal.goal().param_env, pred);
304304
self.with_derived_obligation(obligation, |this| {

compiler/rustc_trait_selection/src/solve/normalize.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,10 @@ where
102102
let infcx = self.at.infcx;
103103
let tcx = infcx.tcx;
104104
let recursion_limit = tcx.recursion_limit();
105+
let alias = alias_term.to_alias_term().unwrap();
105106
if !recursion_limit.value_within_limit(self.depth) {
106-
let term = alias_term.to_alias_term().unwrap();
107-
108107
self.at.infcx.err_ctxt().report_overflow_error(
109-
OverflowCause::DeeplyNormalize(term),
108+
OverflowCause::DeeplyNormalize(alias),
110109
self.at.cause.span,
111110
true,
112111
|_| {},
@@ -120,11 +119,7 @@ where
120119
tcx,
121120
self.at.cause.clone(),
122121
self.at.param_env,
123-
ty::PredicateKind::AliasRelate(
124-
alias_term.into(),
125-
infer_term.into(),
126-
ty::AliasRelationDirection::Equate,
127-
),
122+
ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term: infer_term }),
128123
);
129124

130125
self.fulfill_cx.register_predicate_obligation(infcx, obligation);

0 commit comments

Comments
 (0)