Skip to content

Commit 360dbe5

Browse files
authored
Unrolled build for rust-lang#123363
Rollup merge of rust-lang#123363 - lcnr:normalizes-to-zero-to-inf, r=BoxyUwU change `NormalizesTo` to fully structurally normalize notes in https://hackmd.io/wZ016dE4QKGIhrOnHLlThQ need to also update the dev-guide once this PR lands. in short, the setup is now as follows: `normalizes-to` internally implements one step normalization, applying that normalization to the `goal.predicate.term` causes the projected term to get recursively normalized. With this `normalizes-to` normalizes until the projected term is rigid, meaning that we normalize as many steps necessary, but at least 1. To handle rigid aliases, we add another candidate only if the 1 to inf step normalization failed. With this `normalizes-to` is now full structural normalization. We can now change `AliasRelate` to simply emit `normalizes-to` goals for the rhs and lhs. This avoids the concerns from rust-lang/trait-system-refactor-initiative#103 and generally feels cleaner
2 parents 9cbaa01 + 92b280c commit 360dbe5

15 files changed

+174
-310
lines changed

compiler/rustc_middle/src/traits/solve/inspect.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,6 @@ pub enum ProbeStep<'tcx> {
121121
/// used whenever there are multiple candidates to prove the
122122
/// current goalby .
123123
NestedProbe(Probe<'tcx>),
124-
CommitIfOkStart,
125-
CommitIfOkSuccess,
126124
}
127125

128126
/// What kind of probe we're in. In case the probe represents a candidate, or
@@ -132,6 +130,8 @@ pub enum ProbeStep<'tcx> {
132130
pub enum ProbeKind<'tcx> {
133131
/// The root inference context while proving a goal.
134132
Root { result: QueryResult<'tcx> },
133+
/// Trying to normalize an alias by at least one stpe in `NormalizesTo`.
134+
TryNormalizeNonRigid { result: QueryResult<'tcx> },
135135
/// Probe entered when normalizing the self ty during candidate assembly
136136
NormalizedSelfTyAssembly,
137137
/// Some candidate to prove the current goal.
@@ -143,9 +143,6 @@ pub enum ProbeKind<'tcx> {
143143
/// Used in the probe that wraps normalizing the non-self type for the unsize
144144
/// trait, which is also structurally matched on.
145145
UnsizeAssembly,
146-
/// A call to `EvalCtxt::commit_if_ok` which failed, causing the work
147-
/// to be discarded.
148-
CommitIfOk,
149146
/// During upcasting from some source object to target object type, used to
150147
/// do a probe to find out what projection type(s) may be used to prove that
151148
/// the source type upholds all of the target type's object bounds.

compiler/rustc_middle/src/traits/solve/inspect/format.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
100100
ProbeKind::Root { result } => {
101101
write!(self.f, "ROOT RESULT: {result:?}")
102102
}
103+
ProbeKind::TryNormalizeNonRigid { result } => {
104+
write!(self.f, "TRY NORMALIZE NON-RIGID: {result:?}")
105+
}
103106
ProbeKind::NormalizedSelfTyAssembly => {
104107
write!(self.f, "NORMALIZING SELF TY FOR ASSEMBLY:")
105108
}
@@ -109,9 +112,6 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
109112
ProbeKind::UpcastProjectionCompatibility => {
110113
write!(self.f, "PROBING FOR PROJECTION COMPATIBILITY FOR UPCASTING:")
111114
}
112-
ProbeKind::CommitIfOk => {
113-
write!(self.f, "COMMIT_IF_OK:")
114-
}
115115
ProbeKind::MiscCandidate { name, result } => {
116116
write!(self.f, "CANDIDATE {name}: {result:?}")
117117
}
@@ -132,8 +132,6 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
132132
}
133133
ProbeStep::EvaluateGoals(eval) => this.format_added_goals_evaluation(eval)?,
134134
ProbeStep::NestedProbe(probe) => this.format_probe(probe)?,
135-
ProbeStep::CommitIfOkStart => writeln!(this.f, "COMMIT_IF_OK START")?,
136-
ProbeStep::CommitIfOkSuccess => writeln!(this.f, "COMMIT_IF_OK SUCCESS")?,
137135
}
138136
}
139137
Ok(())

compiler/rustc_trait_selection/src/solve/alias_relate.rs

+34-125
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
//! Doing this via a separate goal is called "deferred alias relation" and part
33
//! of our more general approach to "lazy normalization".
44
//!
5-
//! This is done by first normalizing both sides of the goal, ending up in
6-
//! either a concrete type, rigid alias, or an infer variable.
5+
//! This is done by first structurally normalizing both sides of the goal, ending
6+
//! up in either a concrete type, rigid alias, or an infer variable.
77
//! These are related further according to the rules below:
88
//!
99
//! (1.) If we end up with two rigid aliases, then we relate them structurally.
@@ -14,18 +14,10 @@
1414
//!
1515
//! (3.) Otherwise, if we end with two rigid (non-projection) or infer types,
1616
//! relate them structurally.
17-
//!
18-
//! Subtle: when relating an opaque to another type, we emit a
19-
//! `NormalizesTo(opaque, ?fresh_var)` goal when trying to normalize the opaque.
20-
//! This nested goal starts out as ambiguous and does not actually define the opaque.
21-
//! However, if `?fresh_var` ends up geteting equated to another type, we retry the
22-
//! `NormalizesTo` goal, at which point the opaque is actually defined.
2317
2418
use super::EvalCtxt;
25-
use rustc_infer::traits::query::NoSolution;
26-
use rustc_infer::traits::solve::GoalSource;
2719
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
28-
use rustc_middle::ty::{self, Ty};
20+
use rustc_middle::ty;
2921

3022
impl<'tcx> EvalCtxt<'_, 'tcx> {
3123
#[instrument(level = "debug", skip(self), ret)]
@@ -36,141 +28,58 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
3628
let tcx = self.tcx();
3729
let Goal { param_env, predicate: (lhs, rhs, direction) } = goal;
3830

39-
let Some(lhs) = self.try_normalize_term(param_env, lhs)? else {
40-
return self
41-
.evaluate_added_goals_and_make_canonical_response(Certainty::overflow(true));
31+
// Structurally normalize the lhs.
32+
let lhs = if let Some(alias) = lhs.to_alias_ty(self.tcx()) {
33+
let term = self.next_term_infer_of_kind(lhs);
34+
self.add_normalizes_to_goal(goal.with(tcx, ty::NormalizesTo { alias, term }));
35+
term
36+
} else {
37+
lhs
4238
};
4339

44-
let Some(rhs) = self.try_normalize_term(param_env, rhs)? else {
45-
return self
46-
.evaluate_added_goals_and_make_canonical_response(Certainty::overflow(true));
40+
// Structurally normalize the rhs.
41+
let rhs = if let Some(alias) = rhs.to_alias_ty(self.tcx()) {
42+
let term = self.next_term_infer_of_kind(rhs);
43+
self.add_normalizes_to_goal(goal.with(tcx, ty::NormalizesTo { alias, term }));
44+
term
45+
} else {
46+
rhs
4747
};
4848

49+
// Apply the constraints.
50+
self.try_evaluate_added_goals()?;
51+
let lhs = self.resolve_vars_if_possible(lhs);
52+
let rhs = self.resolve_vars_if_possible(rhs);
53+
debug!(?lhs, ?rhs);
54+
4955
let variance = match direction {
5056
ty::AliasRelationDirection::Equate => ty::Variance::Invariant,
5157
ty::AliasRelationDirection::Subtype => ty::Variance::Covariant,
5258
};
53-
5459
match (lhs.to_alias_ty(tcx), rhs.to_alias_ty(tcx)) {
5560
(None, None) => {
5661
self.relate(param_env, lhs, variance, rhs)?;
5762
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
5863
}
5964

6065
(Some(alias), None) => {
61-
self.relate_rigid_alias_non_alias(param_env, alias, variance, rhs)
66+
self.relate_rigid_alias_non_alias(param_env, alias, variance, rhs)?;
67+
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
68+
}
69+
(None, Some(alias)) => {
70+
self.relate_rigid_alias_non_alias(
71+
param_env,
72+
alias,
73+
variance.xform(ty::Variance::Contravariant),
74+
lhs,
75+
)?;
76+
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
6277
}
63-
(None, Some(alias)) => self.relate_rigid_alias_non_alias(
64-
param_env,
65-
alias,
66-
variance.xform(ty::Variance::Contravariant),
67-
lhs,
68-
),
6978

7079
(Some(alias_lhs), Some(alias_rhs)) => {
7180
self.relate(param_env, alias_lhs, variance, alias_rhs)?;
7281
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
7382
}
7483
}
7584
}
76-
77-
/// Relate a rigid alias with another type. This is the same as
78-
/// an ordinary relate except that we treat the outer most alias
79-
/// constructor as rigid.
80-
#[instrument(level = "debug", skip(self, param_env), ret)]
81-
fn relate_rigid_alias_non_alias(
82-
&mut self,
83-
param_env: ty::ParamEnv<'tcx>,
84-
alias: ty::AliasTy<'tcx>,
85-
variance: ty::Variance,
86-
term: ty::Term<'tcx>,
87-
) -> QueryResult<'tcx> {
88-
// NOTE: this check is purely an optimization, the structural eq would
89-
// always fail if the term is not an inference variable.
90-
if term.is_infer() {
91-
let tcx = self.tcx();
92-
// We need to relate `alias` to `term` treating only the outermost
93-
// constructor as rigid, relating any contained generic arguments as
94-
// normal. We do this by first structurally equating the `term`
95-
// with the alias constructor instantiated with unconstrained infer vars,
96-
// and then relate this with the whole `alias`.
97-
//
98-
// Alternatively we could modify `Equate` for this case by adding another
99-
// variant to `StructurallyRelateAliases`.
100-
let identity_args = self.fresh_args_for_item(alias.def_id);
101-
let rigid_ctor = ty::AliasTy::new(tcx, alias.def_id, identity_args);
102-
self.eq_structurally_relating_aliases(param_env, term, rigid_ctor.to_ty(tcx).into())?;
103-
self.eq(param_env, alias, rigid_ctor)?;
104-
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
105-
} else {
106-
Err(NoSolution)
107-
}
108-
}
109-
110-
// FIXME: This needs a name that reflects that it's okay to bottom-out with an inference var.
111-
/// Normalize the `term` to equate it later.
112-
#[instrument(level = "debug", skip(self, param_env), ret)]
113-
fn try_normalize_term(
114-
&mut self,
115-
param_env: ty::ParamEnv<'tcx>,
116-
term: ty::Term<'tcx>,
117-
) -> Result<Option<ty::Term<'tcx>>, NoSolution> {
118-
match term.unpack() {
119-
ty::TermKind::Ty(ty) => {
120-
Ok(self.try_normalize_ty_recur(param_env, 0, ty).map(Into::into))
121-
}
122-
ty::TermKind::Const(_) => {
123-
if let Some(alias) = term.to_alias_ty(self.tcx()) {
124-
let term = self.next_term_infer_of_kind(term);
125-
self.add_normalizes_to_goal(Goal::new(
126-
self.tcx(),
127-
param_env,
128-
ty::NormalizesTo { alias, term },
129-
));
130-
self.try_evaluate_added_goals()?;
131-
Ok(Some(self.resolve_vars_if_possible(term)))
132-
} else {
133-
Ok(Some(term))
134-
}
135-
}
136-
}
137-
}
138-
139-
#[instrument(level = "debug", skip(self, param_env), ret)]
140-
fn try_normalize_ty_recur(
141-
&mut self,
142-
param_env: ty::ParamEnv<'tcx>,
143-
depth: usize,
144-
ty: Ty<'tcx>,
145-
) -> Option<Ty<'tcx>> {
146-
if !self.tcx().recursion_limit().value_within_limit(depth) {
147-
return None;
148-
}
149-
150-
let ty::Alias(kind, alias) = *ty.kind() else {
151-
return Some(ty);
152-
};
153-
154-
match self.commit_if_ok(|this| {
155-
let tcx = this.tcx();
156-
let normalized_ty = this.next_ty_infer();
157-
let normalizes_to = ty::NormalizesTo { alias, term: normalized_ty.into() };
158-
match kind {
159-
ty::AliasKind::Opaque => {
160-
// HACK: Unlike for associated types, `normalizes-to` for opaques
161-
// is currently not treated as a function. We do not erase the
162-
// expected term.
163-
this.add_goal(GoalSource::Misc, Goal::new(tcx, param_env, normalizes_to));
164-
}
165-
ty::AliasKind::Projection | ty::AliasKind::Inherent | ty::AliasKind::Weak => {
166-
this.add_normalizes_to_goal(Goal::new(tcx, param_env, normalizes_to))
167-
}
168-
}
169-
this.try_evaluate_added_goals()?;
170-
Ok(this.resolve_vars_if_possible(normalized_ty))
171-
}) {
172-
Ok(ty) => self.try_normalize_ty_recur(param_env, depth + 1, ty),
173-
Err(NoSolution) => Some(ty),
174-
}
175-
}
17685
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
332332
/// whether an alias is rigid by using the trait solver. When instantiating a response
333333
/// from the solver we assume that the solver correctly handled aliases and therefore
334334
/// always relate them structurally here.
335-
#[instrument(level = "debug", skip(infcx), ret)]
335+
#[instrument(level = "debug", skip(infcx))]
336336
fn unify_query_var_values(
337337
infcx: &InferCtxt<'tcx>,
338338
param_env: ty::ParamEnv<'tcx>,

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

-47
This file was deleted.

0 commit comments

Comments
 (0)