Skip to content

Commit 101757c

Browse files
committed
setup canonical normalization for const norm
1 parent ade8487 commit 101757c

File tree

5 files changed

+125
-98
lines changed

5 files changed

+125
-98
lines changed

compiler/rustc_middle/src/arena.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ macro_rules! arena_types {
4444
rustc_middle::traits::query::DropckOutlivesResult<'tcx>
4545
>
4646
>,
47-
[] normalize_canonicalized_projection_ty:
47+
[] normalize_canonicalized_projection:
4848
rustc_middle::infer::canonical::Canonical<'tcx,
4949
rustc_middle::infer::canonical::QueryResponse<'tcx,
5050
rustc_middle::traits::query::NormalizationResult<'tcx>

compiler/rustc_middle/src/query/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2411,7 +2411,7 @@ rustc_queries! {
24112411
/// Do not call this query directly: Invoke `normalize` instead.
24122412
///
24132413
/// </div>
2414-
query normalize_canonicalized_projection_ty(
2414+
query normalize_canonicalized_projection(
24152415
goal: CanonicalAliasGoal<'tcx>
24162416
) -> Result<
24172417
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,
@@ -2439,7 +2439,7 @@ rustc_queries! {
24392439
/// Do not call this query directly: Invoke `normalize` instead.
24402440
///
24412441
/// </div>
2442-
query normalize_canonicalized_inherent_projection_ty(
2442+
query normalize_canonicalized_inherent_projection(
24432443
goal: CanonicalAliasGoal<'tcx>
24442444
) -> Result<
24452445
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,

compiler/rustc_middle/src/traits/query.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ pub mod type_op {
6666
}
6767

6868
pub type CanonicalAliasGoal<'tcx> =
69-
CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, ty::AliasTy<'tcx>>>;
69+
CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, ty::AliasTerm<'tcx>>>;
7070

7171
pub type CanonicalMethodAutoderefStepsGoal<'tcx> =
7272
CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, MethodAutoderefSteps<'tcx>>>;
@@ -192,11 +192,11 @@ pub struct MethodAutoderefBadTy<'tcx> {
192192
pub ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
193193
}
194194

195-
/// Result of the `normalize_canonicalized_{{,inherent_}projection,free}_ty` queries.
195+
/// Result of the `normalize_canonicalized_{{,inherent_}projection,free}` queries.
196196
#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
197197
pub struct NormalizationResult<'tcx> {
198198
/// Result of the normalization.
199-
pub normalized_ty: Ty<'tcx>,
199+
pub normalized_term: ty::Term<'tcx>,
200200
}
201201

202202
/// Outlives bounds are relationships between generic parameters,

compiler/rustc_trait_selection/src/traits/query/normalize.rs

Lines changed: 103 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
//! Code for the 'normalization' query. This consists of a wrapper
22
//! which folds deeply, invoking the underlying
3-
//! `normalize_canonicalized_projection_ty` query when it encounters projections.
3+
//! `normalize_canonicalized_projection` query when it encounters projections.
44
55
use rustc_data_structures::sso::SsoHashMap;
66
use rustc_data_structures::stack::ensure_sufficient_stack;
7+
use rustc_hir::def::DefKind;
78
use rustc_infer::traits::PredicateObligations;
89
use rustc_macros::extension;
910
pub use rustc_middle::traits::query::NormalizationResult;
@@ -253,76 +254,9 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
253254
}
254255
}
255256

256-
ty::Projection | ty::Inherent | ty::Free => {
257-
// See note in `rustc_trait_selection::traits::project`
258-
259-
let infcx = self.infcx;
260-
let tcx = infcx.tcx;
261-
// Just an optimization: When we don't have escaping bound vars,
262-
// we don't need to replace them with placeholders.
263-
let (data, maps) = if data.has_escaping_bound_vars() {
264-
let (data, mapped_regions, mapped_types, mapped_consts) =
265-
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
266-
(data, Some((mapped_regions, mapped_types, mapped_consts)))
267-
} else {
268-
(data, None)
269-
};
270-
let data = data.try_fold_with(self)?;
271-
272-
let mut orig_values = OriginalQueryValues::default();
273-
let c_data = infcx.canonicalize_query(self.param_env.and(data), &mut orig_values);
274-
debug!("QueryNormalizer: c_data = {:#?}", c_data);
275-
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
276-
let result = match kind {
277-
ty::Projection => tcx.normalize_canonicalized_projection_ty(c_data),
278-
ty::Free => tcx.normalize_canonicalized_free_alias(c_data),
279-
ty::Inherent => tcx.normalize_canonicalized_inherent_projection_ty(c_data),
280-
kind => unreachable!("did not expect {kind:?} due to match arm above"),
281-
}?;
282-
// We don't expect ambiguity.
283-
if !result.value.is_proven() {
284-
// Rustdoc normalizes possibly not well-formed types, so only
285-
// treat this as a bug if we're not in rustdoc.
286-
if !tcx.sess.opts.actually_rustdoc {
287-
tcx.dcx()
288-
.delayed_bug(format!("unexpected ambiguity: {c_data:?} {result:?}"));
289-
}
290-
return Err(NoSolution);
291-
}
292-
let InferOk { value: result, obligations } = infcx
293-
.instantiate_query_response_and_region_obligations(
294-
self.cause,
295-
self.param_env,
296-
&orig_values,
297-
result,
298-
)?;
299-
debug!("QueryNormalizer: result = {:#?}", result);
300-
debug!("QueryNormalizer: obligations = {:#?}", obligations);
301-
self.obligations.extend(obligations);
302-
let res = if let Some((mapped_regions, mapped_types, mapped_consts)) = maps {
303-
PlaceholderReplacer::replace_placeholders(
304-
infcx,
305-
mapped_regions,
306-
mapped_types,
307-
mapped_consts,
308-
&self.universes,
309-
result.normalized_ty,
310-
)
311-
} else {
312-
result.normalized_ty
313-
};
314-
// `tcx.normalize_canonicalized_projection_ty` may normalize to a type that
315-
// still has unevaluated consts, so keep normalizing here if that's the case.
316-
// Similarly, `tcx.normalize_canonicalized_free_alias` will only unwrap one layer
317-
// of type and we need to continue folding it to reveal the TAIT behind it.
318-
if res != ty
319-
&& (res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) || kind == ty::Free)
320-
{
321-
res.try_fold_with(self)?
322-
} else {
323-
res
324-
}
325-
}
257+
ty::Projection | ty::Inherent | ty::Free => self
258+
.try_fold_free_or_assoc(ty::AliasTerm::new(self.cx(), data.def_id, data.args))?
259+
.expect_type(),
326260
};
327261

328262
self.cache.insert(ty, res);
@@ -337,12 +271,22 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
337271
return Ok(constant);
338272
}
339273

340-
let constant = crate::traits::with_replaced_escaping_bound_vars(
341-
self.infcx,
342-
&mut self.universes,
343-
constant,
344-
|constant| crate::traits::evaluate_const(&self.infcx, constant, self.param_env),
345-
);
274+
let uv = match constant.kind() {
275+
ty::ConstKind::Unevaluated(uv) => uv,
276+
_ => return constant.try_super_fold_with(self),
277+
};
278+
279+
let constant = match self.cx().def_kind(uv.def) {
280+
DefKind::AnonConst => crate::traits::with_replaced_escaping_bound_vars(
281+
self.infcx,
282+
&mut self.universes,
283+
constant,
284+
|constant| crate::traits::evaluate_const(&self.infcx, constant, self.param_env),
285+
),
286+
_ => self
287+
.try_fold_free_or_assoc(ty::AliasTerm::new(self.cx(), uv.def, uv.args))?
288+
.expect_const(),
289+
};
346290
debug!(?constant, ?self.param_env);
347291
constant.try_super_fold_with(self)
348292
}
@@ -359,3 +303,85 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'a, 'tcx> {
359303
}
360304
}
361305
}
306+
307+
impl<'a, 'tcx> QueryNormalizer<'a, 'tcx> {
308+
fn try_fold_free_or_assoc(
309+
&mut self,
310+
term: ty::AliasTerm<'tcx>,
311+
) -> Result<ty::Term<'tcx>, NoSolution> {
312+
let infcx = self.infcx;
313+
let tcx = infcx.tcx;
314+
// Just an optimization: When we don't have escaping bound vars,
315+
// we don't need to replace them with placeholders.
316+
let (term, maps) = if term.has_escaping_bound_vars() {
317+
let (term, mapped_regions, mapped_types, mapped_consts) =
318+
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, term);
319+
(term, Some((mapped_regions, mapped_types, mapped_consts)))
320+
} else {
321+
(term, None)
322+
};
323+
let term = term.try_fold_with(self)?;
324+
325+
let mut orig_values = OriginalQueryValues::default();
326+
let c_term = infcx.canonicalize_query(self.param_env.and(term), &mut orig_values);
327+
debug!("QueryNormalizer: c_term = {:#?}", c_term);
328+
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
329+
let result = match term.kind(tcx) {
330+
ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => {
331+
tcx.normalize_canonicalized_projection(c_term)
332+
}
333+
ty::AliasTermKind::FreeTy | ty::AliasTermKind::FreeConst => {
334+
tcx.normalize_canonicalized_free_alias(c_term)
335+
}
336+
ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst => {
337+
tcx.normalize_canonicalized_inherent_projection(c_term)
338+
}
339+
kind @ (ty::AliasTermKind::OpaqueTy | ty::AliasTermKind::UnevaluatedConst) => {
340+
unreachable!("did not expect {kind:?} due to match arm above")
341+
}
342+
}?;
343+
// We don't expect ambiguity.
344+
if !result.value.is_proven() {
345+
// Rustdoc normalizes possibly not well-formed types, so only
346+
// treat this as a bug if we're not in rustdoc.
347+
if !tcx.sess.opts.actually_rustdoc {
348+
tcx.dcx().delayed_bug(format!("unexpected ambiguity: {c_term:?} {result:?}"));
349+
}
350+
return Err(NoSolution);
351+
}
352+
let InferOk { value: result, obligations } = infcx
353+
.instantiate_query_response_and_region_obligations(
354+
self.cause,
355+
self.param_env,
356+
&orig_values,
357+
result,
358+
)?;
359+
debug!("QueryNormalizer: result = {:#?}", result);
360+
debug!("QueryNormalizer: obligations = {:#?}", obligations);
361+
self.obligations.extend(obligations);
362+
let res = if let Some((mapped_regions, mapped_types, mapped_consts)) = maps {
363+
PlaceholderReplacer::replace_placeholders(
364+
infcx,
365+
mapped_regions,
366+
mapped_types,
367+
mapped_consts,
368+
&self.universes,
369+
result.normalized_term,
370+
)
371+
} else {
372+
result.normalized_term
373+
};
374+
// `tcx.normalize_canonicalized_projection` may normalize to a type that
375+
// still has unevaluated consts, so keep normalizing here if that's the case.
376+
// Similarly, `tcx.normalize_canonicalized_free_alias` will only unwrap one layer
377+
// of type and we need to continue folding it to reveal the TAIT behind it.
378+
if res != term.to_term(tcx)
379+
&& (res.as_type().map_or(false, |t| t.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION))
380+
|| term.kind(tcx) == ty::AliasTermKind::FreeTy)
381+
{
382+
res.try_fold_with(self)
383+
} else {
384+
Ok(res)
385+
}
386+
}
387+
}

compiler/rustc_traits/src/normalize_projection_ty.rs

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,18 @@ use tracing::debug;
1212

1313
pub(crate) fn provide(p: &mut Providers) {
1414
*p = Providers {
15-
normalize_canonicalized_projection_ty,
15+
normalize_canonicalized_projection,
1616
normalize_canonicalized_free_alias,
17-
normalize_canonicalized_inherent_projection_ty,
17+
normalize_canonicalized_inherent_projection,
1818
..*p
1919
};
2020
}
2121

22-
fn normalize_canonicalized_projection_ty<'tcx>(
22+
fn normalize_canonicalized_projection<'tcx>(
2323
tcx: TyCtxt<'tcx>,
2424
goal: CanonicalAliasGoal<'tcx>,
2525
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> {
26-
debug!("normalize_canonicalized_projection_ty(goal={:#?})", goal);
26+
debug!("normalize_canonicalized_projection(goal={:#?})", goal);
2727

2828
tcx.infer_ctxt().enter_canonical_trait_query(
2929
&goal,
@@ -32,7 +32,7 @@ fn normalize_canonicalized_projection_ty<'tcx>(
3232
let selcx = &mut SelectionContext::new(ocx.infcx);
3333
let cause = ObligationCause::dummy();
3434
let mut obligations = PredicateObligations::new();
35-
let answer = traits::normalize_projection_term(
35+
let normalized_term = traits::normalize_projection_term(
3636
selcx,
3737
param_env,
3838
goal.into(),
@@ -61,10 +61,7 @@ fn normalize_canonicalized_projection_ty<'tcx>(
6161
return Err(NoSolution);
6262
}
6363

64-
// FIXME(associated_const_equality): All users of normalize_canonicalized_projection_ty
65-
// expected a type, but there is the possibility it could've been a const now.
66-
// Maybe change it to a Term later?
67-
Ok(NormalizationResult { normalized_ty: answer.expect_type() })
64+
Ok(NormalizationResult { normalized_term })
6865
},
6966
)
7067
}
@@ -89,25 +86,29 @@ fn normalize_canonicalized_free_alias<'tcx>(
8986
},
9087
);
9188
ocx.register_obligations(obligations);
92-
let normalized_ty = tcx.type_of(goal.def_id).instantiate(tcx, goal.args);
93-
Ok(NormalizationResult { normalized_ty })
89+
let normalized_term = if goal.kind(tcx).is_type() {
90+
tcx.type_of(goal.def_id).instantiate(tcx, goal.args).into()
91+
} else {
92+
todo!()
93+
};
94+
Ok(NormalizationResult { normalized_term })
9495
},
9596
)
9697
}
9798

98-
fn normalize_canonicalized_inherent_projection_ty<'tcx>(
99+
fn normalize_canonicalized_inherent_projection<'tcx>(
99100
tcx: TyCtxt<'tcx>,
100101
goal: CanonicalAliasGoal<'tcx>,
101102
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> {
102-
debug!("normalize_canonicalized_inherent_projection_ty(goal={:#?})", goal);
103+
debug!("normalize_canonicalized_inherent_projection(goal={:#?})", goal);
103104

104105
tcx.infer_ctxt().enter_canonical_trait_query(
105106
&goal,
106107
|ocx, ParamEnvAnd { param_env, value: goal }| {
107108
let selcx = &mut SelectionContext::new(ocx.infcx);
108109
let cause = ObligationCause::dummy();
109110
let mut obligations = PredicateObligations::new();
110-
let answer = traits::normalize_inherent_projection(
111+
let normalized_term = traits::normalize_inherent_projection(
111112
selcx,
112113
param_env,
113114
goal.into(),
@@ -117,7 +118,7 @@ fn normalize_canonicalized_inherent_projection_ty<'tcx>(
117118
);
118119
ocx.register_obligations(obligations);
119120

120-
Ok(NormalizationResult { normalized_ty: answer.expect_type() })
121+
Ok(NormalizationResult { normalized_term })
121122
},
122123
)
123124
}

0 commit comments

Comments
 (0)