Skip to content

Commit 92b280c

Browse files
committed
normalizes-to change from '1' to '0 to inf' steps
1 parent d99c775 commit 92b280c

File tree

12 files changed

+148
-296
lines changed

12 files changed

+148
-296
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-117
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,17 +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;
2619
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
27-
use rustc_middle::ty::{self, Ty};
20+
use rustc_middle::ty;
2821

2922
impl<'tcx> EvalCtxt<'_, 'tcx> {
3023
#[instrument(level = "debug", skip(self), ret)]
@@ -35,134 +28,58 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
3528
let tcx = self.tcx();
3629
let Goal { param_env, predicate: (lhs, rhs, direction) } = goal;
3730

38-
let Some(lhs) = self.try_normalize_term(param_env, lhs)? else {
39-
return self
40-
.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
4138
};
4239

43-
let Some(rhs) = self.try_normalize_term(param_env, rhs)? else {
44-
return self
45-
.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
4647
};
4748

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+
4855
let variance = match direction {
4956
ty::AliasRelationDirection::Equate => ty::Variance::Invariant,
5057
ty::AliasRelationDirection::Subtype => ty::Variance::Covariant,
5158
};
52-
5359
match (lhs.to_alias_ty(tcx), rhs.to_alias_ty(tcx)) {
5460
(None, None) => {
5561
self.relate(param_env, lhs, variance, rhs)?;
5662
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
5763
}
5864

5965
(Some(alias), None) => {
60-
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)
6177
}
62-
(None, Some(alias)) => self.relate_rigid_alias_non_alias(
63-
param_env,
64-
alias,
65-
variance.xform(ty::Variance::Contravariant),
66-
lhs,
67-
),
6878

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

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)