1use rustc_data_structures::stack::ensure_sufficient_stack;
4use rustc_hir::def::DefKind;
5use rustc_infer::infer::at::At;
6use rustc_infer::infer::{InferCtxt, InferOk};
7use rustc_infer::traits::{
8 FromSolverError, Normalized, Obligation, PredicateObligations, TraitEngine,
9};
10use rustc_macros::extension;
11use rustc_middle::span_bug;
12use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
13use rustc_middle::ty::{
14 self, AliasTerm, Term, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
15 TypeVisitableExt, TypingMode,
16};
17use tracing::{debug, instrument};
18
19use super::{BoundVarReplacer, PlaceholderReplacer, SelectionContext, project};
20use crate::error_reporting::InferCtxtErrorExt;
21use crate::error_reporting::traits::OverflowCause;
22use crate::solve::NextSolverError;
23
24#[extension(pub trait NormalizeExt<'tcx>)]
25impl<'tcx> At<'_, 'tcx> {
26 fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> InferOk<'tcx, T> {
31 if self.infcx.next_trait_solver() {
32 InferOk { value, obligations: PredicateObligations::new() }
33 } else {
34 let mut selcx = SelectionContext::new(self.infcx);
35 let Normalized { value, obligations } =
36 normalize_with_depth(&mut selcx, self.param_env, self.cause.clone(), 0, value);
37 InferOk { value, obligations }
38 }
39 }
40
41 fn deeply_normalize<T, E>(
54 self,
55 value: T,
56 fulfill_cx: &mut dyn TraitEngine<'tcx, E>,
57 ) -> Result<T, Vec<E>>
58 where
59 T: TypeFoldable<TyCtxt<'tcx>>,
60 E: FromSolverError<'tcx, NextSolverError<'tcx>>,
61 {
62 if self.infcx.next_trait_solver() {
63 crate::solve::deeply_normalize(self, value)
64 } else {
65 if fulfill_cx.has_pending_obligations() {
66 let pending_obligations = fulfill_cx.pending_obligations();
67 span_bug!(
68 pending_obligations[0].cause.span,
69 "deeply_normalize should not be called with pending obligations: \
70 {pending_obligations:#?}"
71 );
72 }
73 let value = self
74 .normalize(value)
75 .into_value_registering_obligations(self.infcx, &mut *fulfill_cx);
76 let errors = fulfill_cx.select_all_or_error(self.infcx);
77 let value = self.infcx.resolve_vars_if_possible(value);
78 if errors.is_empty() {
79 Ok(value)
80 } else {
81 let _ = fulfill_cx.collect_remaining_errors(self.infcx);
85 Err(errors)
86 }
87 }
88 }
89}
90
91pub(crate) fn normalize_with_depth<'a, 'b, 'tcx, T>(
93 selcx: &'a mut SelectionContext<'b, 'tcx>,
94 param_env: ty::ParamEnv<'tcx>,
95 cause: ObligationCause<'tcx>,
96 depth: usize,
97 value: T,
98) -> Normalized<'tcx, T>
99where
100 T: TypeFoldable<TyCtxt<'tcx>>,
101{
102 let mut obligations = PredicateObligations::new();
103 let value = normalize_with_depth_to(selcx, param_env, cause, depth, value, &mut obligations);
104 Normalized { value, obligations }
105}
106
107#[instrument(level = "info", skip(selcx, param_env, cause, obligations))]
108pub(crate) fn normalize_with_depth_to<'a, 'b, 'tcx, T>(
109 selcx: &'a mut SelectionContext<'b, 'tcx>,
110 param_env: ty::ParamEnv<'tcx>,
111 cause: ObligationCause<'tcx>,
112 depth: usize,
113 value: T,
114 obligations: &mut PredicateObligations<'tcx>,
115) -> T
116where
117 T: TypeFoldable<TyCtxt<'tcx>>,
118{
119 debug!(obligations.len = obligations.len());
120 let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations);
121 let result = ensure_sufficient_stack(|| AssocTypeNormalizer::fold(&mut normalizer, value));
122 debug!(?result, obligations.len = normalizer.obligations.len());
123 debug!(?normalizer.obligations,);
124 result
125}
126
127pub(super) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
128 infcx: &InferCtxt<'tcx>,
129 value: &T,
130) -> bool {
131 let mut flags = ty::TypeFlags::HAS_ALIAS;
132
133 match infcx.typing_mode() {
136 TypingMode::Coherence
138 | TypingMode::Analysis { .. }
139 | TypingMode::Borrowck { .. }
140 | TypingMode::PostBorrowckAnalysis { .. } => flags.remove(ty::TypeFlags::HAS_TY_OPAQUE),
141 TypingMode::PostAnalysis => {}
142 }
143
144 value.has_type_flags(flags)
145}
146
147struct AssocTypeNormalizer<'a, 'b, 'tcx> {
148 selcx: &'a mut SelectionContext<'b, 'tcx>,
149 param_env: ty::ParamEnv<'tcx>,
150 cause: ObligationCause<'tcx>,
151 obligations: &'a mut PredicateObligations<'tcx>,
152 depth: usize,
153 universes: Vec<Option<ty::UniverseIndex>>,
154}
155
156impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
157 fn new(
158 selcx: &'a mut SelectionContext<'b, 'tcx>,
159 param_env: ty::ParamEnv<'tcx>,
160 cause: ObligationCause<'tcx>,
161 depth: usize,
162 obligations: &'a mut PredicateObligations<'tcx>,
163 ) -> AssocTypeNormalizer<'a, 'b, 'tcx> {
164 debug_assert!(!selcx.infcx.next_trait_solver());
165 AssocTypeNormalizer { selcx, param_env, cause, obligations, depth, universes: vec![] }
166 }
167
168 fn fold<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, value: T) -> T {
169 let value = self.selcx.infcx.resolve_vars_if_possible(value);
170 debug!(?value);
171
172 assert!(
173 !value.has_escaping_bound_vars(),
174 "Normalizing {value:?} without wrapping in a `Binder`"
175 );
176
177 if !needs_normalization(self.selcx.infcx, &value) { value } else { value.fold_with(self) }
178 }
179
180 #[instrument(level = "debug", skip(self), ret)]
182 fn normalize_trait_projection(&mut self, proj: AliasTerm<'tcx>) -> Term<'tcx> {
183 if !proj.has_escaping_bound_vars() {
184 let proj = proj.fold_with(self);
193 project::normalize_projection_term(
194 self.selcx,
195 self.param_env,
196 proj,
197 self.cause.clone(),
198 self.depth,
199 self.obligations,
200 )
201 } else {
202 let infcx = self.selcx.infcx;
214 let (proj, mapped_regions, mapped_types, mapped_consts) =
215 BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, proj);
216 let proj = proj.fold_with(self);
217 let normalized_term = project::opt_normalize_projection_term(
218 self.selcx,
219 self.param_env,
220 proj,
221 self.cause.clone(),
222 self.depth,
223 self.obligations,
224 )
225 .ok()
226 .flatten()
227 .unwrap_or(proj.to_term(infcx.tcx));
228
229 PlaceholderReplacer::replace_placeholders(
230 infcx,
231 mapped_regions,
232 mapped_types,
233 mapped_consts,
234 &self.universes,
235 normalized_term,
236 )
237 }
238 }
239
240 #[instrument(level = "debug", skip(self), ret)]
242 fn normalize_inherent_projection(&mut self, inherent: AliasTerm<'tcx>) -> Term<'tcx> {
243 if !inherent.has_escaping_bound_vars() {
244 let inherent = inherent.fold_with(self);
254 project::normalize_inherent_projection(
255 self.selcx,
256 self.param_env,
257 inherent,
258 self.cause.clone(),
259 self.depth,
260 self.obligations,
261 )
262 } else {
263 let infcx = self.selcx.infcx;
264 let (inherent, mapped_regions, mapped_types, mapped_consts) =
265 BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, inherent);
266 let inherent = inherent.fold_with(self);
267 let inherent = project::normalize_inherent_projection(
268 self.selcx,
269 self.param_env,
270 inherent,
271 self.cause.clone(),
272 self.depth,
273 self.obligations,
274 );
275
276 PlaceholderReplacer::replace_placeholders(
277 infcx,
278 mapped_regions,
279 mapped_types,
280 mapped_consts,
281 &self.universes,
282 inherent,
283 )
284 }
285 }
286
287 #[instrument(level = "debug", skip(self), ret)]
289 fn normalize_free_alias(&mut self, free: AliasTerm<'tcx>) -> Term<'tcx> {
290 let recursion_limit = self.cx().recursion_limit();
291 if !recursion_limit.value_within_limit(self.depth) {
292 self.selcx.infcx.err_ctxt().report_overflow_error(
293 OverflowCause::DeeplyNormalize(free.into()),
294 self.cause.span,
295 false,
296 |diag| {
297 diag.note(crate::fluent_generated::trait_selection_ty_alias_overflow);
298 },
299 );
300 }
301
302 let infcx = self.selcx.infcx;
316 self.obligations.extend(
317 infcx.tcx.predicates_of(free.def_id).instantiate_own(infcx.tcx, free.args).map(
318 |(mut predicate, span)| {
319 if free.has_escaping_bound_vars() {
320 (predicate, ..) = BoundVarReplacer::replace_bound_vars(
321 infcx,
322 &mut self.universes,
323 predicate,
324 );
325 }
326 let mut cause = self.cause.clone();
327 cause.map_code(|code| ObligationCauseCode::TypeAlias(code, span, free.def_id));
328 Obligation::new(infcx.tcx, cause, self.param_env, predicate)
329 },
330 ),
331 );
332 self.depth += 1;
333 let res = if free.kind(infcx.tcx).is_type() {
334 infcx.tcx.type_of(free.def_id).instantiate(infcx.tcx, free.args).fold_with(self).into()
335 } else {
336 super::evaluate_const(infcx, free.to_term(infcx.tcx).expect_const(), self.param_env)
339 .super_fold_with(self)
340 .into()
341 };
342 self.depth -= 1;
343 res
344 }
345}
346
347impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx> {
348 fn cx(&self) -> TyCtxt<'tcx> {
349 self.selcx.tcx()
350 }
351
352 fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
353 &mut self,
354 t: ty::Binder<'tcx, T>,
355 ) -> ty::Binder<'tcx, T> {
356 self.universes.push(None);
357 let t = t.super_fold_with(self);
358 self.universes.pop();
359 t
360 }
361
362 fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
363 if !needs_normalization(self.selcx.infcx, &ty) {
364 return ty;
365 }
366
367 let (kind, data) = match *ty.kind() {
368 ty::Alias(kind, data) => (kind, data),
369 _ => return ty.super_fold_with(self),
370 };
371
372 match kind {
396 ty::Opaque => {
397 match self.selcx.infcx.typing_mode() {
399 TypingMode::Coherence
401 | TypingMode::Analysis { .. }
402 | TypingMode::Borrowck { .. }
403 | TypingMode::PostBorrowckAnalysis { .. } => ty.super_fold_with(self),
404 TypingMode::PostAnalysis => {
405 let recursion_limit = self.cx().recursion_limit();
406 if !recursion_limit.value_within_limit(self.depth) {
407 self.selcx.infcx.err_ctxt().report_overflow_error(
408 OverflowCause::DeeplyNormalize(data.into()),
409 self.cause.span,
410 true,
411 |_| {},
412 );
413 }
414
415 let args = data.args.fold_with(self);
416 let generic_ty = self.cx().type_of(data.def_id);
417 let concrete_ty = generic_ty.instantiate(self.cx(), args);
418 self.depth += 1;
419 let folded_ty = self.fold_ty(concrete_ty);
420 self.depth -= 1;
421 folded_ty
422 }
423 }
424 }
425
426 ty::Projection => self.normalize_trait_projection(data.into()).expect_type(),
427 ty::Inherent => self.normalize_inherent_projection(data.into()).expect_type(),
428 ty::Free => self.normalize_free_alias(data.into()).expect_type(),
429 }
430 }
431
432 #[instrument(skip(self), level = "debug")]
433 fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
434 let tcx = self.selcx.tcx();
435 if tcx.features().generic_const_exprs() || !needs_normalization(self.selcx.infcx, &ct) {
436 return ct;
437 }
438
439 if tcx.features().min_generic_const_args() {
447 let uv = match ct.kind() {
448 ty::ConstKind::Unevaluated(uv) => uv,
449 _ => return ct.super_fold_with(self),
450 };
451
452 let ct = match tcx.def_kind(uv.def) {
453 DefKind::AssocConst => match tcx.def_kind(tcx.parent(uv.def)) {
454 DefKind::Trait => self.normalize_trait_projection(uv.into()),
455 DefKind::Impl { of_trait: false } => {
456 self.normalize_inherent_projection(uv.into())
457 }
458 kind => unreachable!(
459 "unexpected `DefKind` for const alias' resolution's parent def: {:?}",
460 kind
461 ),
462 },
463 DefKind::Const | DefKind::AnonConst => self.normalize_free_alias(uv.into()),
464 kind => {
465 unreachable!("unexpected `DefKind` for const alias to resolve to: {:?}", kind)
466 }
467 };
468
469 ct.expect_const().super_fold_with(self)
472 } else {
473 let ct = ct.super_fold_with(self);
474 return super::with_replaced_escaping_bound_vars(
475 self.selcx.infcx,
476 &mut self.universes,
477 ct,
478 |ct| super::evaluate_const(self.selcx.infcx, ct, self.param_env),
479 )
480 .super_fold_with(self);
481 }
484 }
485
486 #[inline]
487 fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
488 if p.allow_normalization() && needs_normalization(self.selcx.infcx, &p) {
489 p.super_fold_with(self)
490 } else {
491 p
492 }
493 }
494}