rustc_trait_selection/solve/
normalize.rs1use rustc_infer::infer::InferCtxt;
2use rustc_infer::infer::at::At;
3use rustc_infer::traits::solve::Goal;
4use rustc_infer::traits::{
5 FromSolverError, Normalized, Obligation, PredicateObligations, TraitEngine,
6};
7use rustc_middle::traits::ObligationCause;
8use rustc_middle::ty::{
9 self, Binder, Flags, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
10 UniverseIndex, Unnormalized,
11};
12use rustc_next_trait_solver::normalize::{NormalizationFolder, NormalizationWasAmbiguous};
13use rustc_next_trait_solver::solve::SolverDelegateEvalExt;
14
15use super::{FulfillmentCtxt, NextSolverError};
16use crate::solve::{Certainty, SolverDelegate};
17use crate::traits::{BoundVarReplacer, ScrubbedTraitError};
18
19pub fn normalize<'tcx, T>(at: At<'_, 'tcx>, value: Unnormalized<'tcx, T>) -> Normalized<'tcx, T>
21where
22 T: TypeFoldable<TyCtxt<'tcx>>,
23{
24 normalize_with_universes(at, value, ::alloc::vec::Vec::new()vec![])
25}
26
27fn normalize_with_universes<'tcx, T>(
35 at: At<'_, 'tcx>,
36 value: Unnormalized<'tcx, T>,
37 universes: Vec<Option<UniverseIndex>>,
38) -> Normalized<'tcx, T>
39where
40 T: TypeFoldable<TyCtxt<'tcx>>,
41{
42 let infcx = at.infcx;
43 let value = value.skip_normalization();
44 let value = infcx.resolve_vars_if_possible(value);
45
46 if !infcx.tcx.renormalize_rigid_aliases() && !value.has_non_rigid_aliases() {
47 return Normalized { value, obligations: Default::default() };
48 }
49
50 let original_value = value.clone();
51 let mut stalled_goals = ::alloc::vec::Vec::new()vec![];
52 let mut folder = NormalizationFolder::new(infcx, universes.clone(), |alias_term| {
53 let delegate = <&SolverDelegate<'tcx>>::from(infcx);
54 let infer_term = delegate.next_term_var_of_alias_kind(alias_term, at.cause.span);
55 let predicate = ty::ProjectionPredicate { projection_term: alias_term, term: infer_term };
56 let goal = Goal::new(infcx.tcx, at.param_env, predicate);
57 let result = match delegate.evaluate_root_goal(goal, at.cause.span, None) {
58 Ok(result) => result,
59 Err(err) => return Err(err),
60 };
61 let normalized = infcx.resolve_vars_if_possible(infer_term);
62 let normalization_was_ambiguous = match result.certainty {
63 Certainty::Yes => NormalizationWasAmbiguous::No,
64 Certainty::Maybe { .. } => {
65 stalled_goals.push(result.goal);
66 NormalizationWasAmbiguous::Yes
67 }
68 };
69 Ok((normalized, normalization_was_ambiguous))
70 });
71 if let Ok(value) = value.try_fold_with(&mut folder) {
72 let obligations = stalled_goals
73 .into_iter()
74 .map(|goal| {
75 Obligation::new(infcx.tcx, at.cause.clone(), goal.param_env, goal.predicate)
76 })
77 .collect();
78 Normalized { value, obligations }
79 } else {
80 let mut replacer = ReplaceAliasWithInfer { at, obligations: Default::default(), universes };
81 let value = original_value.fold_with(&mut replacer);
82 Normalized { value, obligations: replacer.obligations }
83 }
84}
85
86struct ReplaceAliasWithInfer<'me, 'tcx> {
87 at: At<'me, 'tcx>,
88 obligations: PredicateObligations<'tcx>,
89 universes: Vec<Option<UniverseIndex>>,
90}
91
92impl<'me, 'tcx> ReplaceAliasWithInfer<'me, 'tcx> {
93 fn term_to_infer(&mut self, alias_term: ty::AliasTerm<'tcx>) -> ty::Term<'tcx> {
94 let infcx = self.at.infcx;
95 let infer_term = infcx.next_term_var_of_alias_kind(alias_term, self.at.cause.span);
96 let obligation = Obligation::new(
97 infcx.tcx,
98 self.at.cause.clone(),
99 self.at.param_env,
100 ty::ProjectionPredicate { projection_term: alias_term, term: infer_term },
101 );
102 self.obligations.push(obligation);
103 infer_term
104 }
105}
106
107impl<'me, 'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceAliasWithInfer<'me, 'tcx> {
108 fn cx(&self) -> TyCtxt<'tcx> {
109 self.at.infcx.tcx
110 }
111
112 fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
113 &mut self,
114 t: Binder<'tcx, T>,
115 ) -> Binder<'tcx, T> {
116 self.universes.push(None);
117 let t = t.super_fold_with(self);
118 self.universes.pop();
119 t
120 }
121
122 fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
123 if !self.cx().renormalize_rigid_aliases() && !ty.has_non_rigid_aliases() {
124 return ty;
125 }
126
127 let ty = ty.super_fold_with(self);
128 let ty::Alias(orig_is_rigid, alias) = *ty.kind() else { return ty };
129 if !self.cx().renormalize_rigid_aliases() && orig_is_rigid == ty::IsRigid::Yes {
130 return ty;
131 }
132
133 if ty.has_escaping_bound_vars() {
134 let (replaced, ..) =
135 BoundVarReplacer::replace_bound_vars(self.at.infcx, &mut self.universes, alias);
136 let _ = self.term_to_infer(replaced.into());
137 ty
138 } else {
139 self.term_to_infer(alias.into()).expect_type()
140 }
141 }
142
143 fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
144 if !self.cx().renormalize_rigid_aliases() && !ct.has_non_rigid_aliases() {
145 return ct;
146 }
147
148 let ct = ct.super_fold_with(self);
149 let ty::ConstKind::Unevaluated(orig_is_rigid, uv) = ct.kind() else { return ct };
150 if !self.cx().renormalize_rigid_aliases() && orig_is_rigid == ty::IsRigid::Yes {
151 return ct;
152 }
153
154 if ct.has_escaping_bound_vars() {
155 let (replaced, ..) =
156 BoundVarReplacer::replace_bound_vars(self.at.infcx, &mut self.universes, uv);
157 let _ = self.term_to_infer(replaced.into());
158 ct
159 } else {
160 self.term_to_infer(uv.into()).expect_const()
161 }
162 }
163}
164
165pub fn deeply_normalize<'tcx, T, E>(
168 at: At<'_, 'tcx>,
169 value: Unnormalized<'tcx, T>,
170) -> Result<T, Vec<E>>
171where
172 T: TypeFoldable<TyCtxt<'tcx>>,
173 E: FromSolverError<'tcx, NextSolverError<'tcx>>,
174{
175 if !!value.as_ref().skip_normalization().has_escaping_bound_vars() {
::core::panicking::panic("assertion failed: !value.as_ref().skip_normalization().has_escaping_bound_vars()")
};assert!(!value.as_ref().skip_normalization().has_escaping_bound_vars());
176 deeply_normalize_with_skipped_universes(at, value, ::alloc::vec::Vec::new()vec![])
177}
178
179pub fn deeply_normalize_with_skipped_universes<'tcx, T, E>(
186 at: At<'_, 'tcx>,
187 value: Unnormalized<'tcx, T>,
188 universes: Vec<Option<UniverseIndex>>,
189) -> Result<T, Vec<E>>
190where
191 T: TypeFoldable<TyCtxt<'tcx>>,
192 E: FromSolverError<'tcx, NextSolverError<'tcx>>,
193{
194 let (value, coroutine_goals) =
195 deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals(
196 at, value, universes,
197 )?;
198 {
match (&coroutine_goals, &::alloc::vec::Vec::new()) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(coroutine_goals, vec![]);
199
200 Ok(value)
201}
202
203pub fn deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals<'tcx, T, E>(
213 at: At<'_, 'tcx>,
214 value: Unnormalized<'tcx, T>,
215 universes: Vec<Option<UniverseIndex>>,
216) -> Result<(T, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), Vec<E>>
217where
218 T: TypeFoldable<TyCtxt<'tcx>>,
219 E: FromSolverError<'tcx, NextSolverError<'tcx>>,
220{
221 let Normalized { value, obligations } = normalize_with_universes(at, value, universes);
222
223 let mut fulfill_cx = FulfillmentCtxt::new(at.infcx);
224 for pred in obligations {
225 fulfill_cx.register_predicate_obligation(at.infcx, pred);
226 }
227
228 let errors = fulfill_cx.try_evaluate_obligations(at.infcx);
229 if !errors.is_empty() {
230 return Err(errors);
231 }
232
233 let stalled_coroutine_goals = fulfill_cx
234 .drain_stalled_obligations_for_coroutines(at.infcx)
235 .into_iter()
236 .map(|obl| obl.as_goal())
237 .collect();
238
239 let errors = fulfill_cx.collect_remaining_errors(at.infcx);
240 if !errors.is_empty() {
241 return Err(errors);
242 }
243
244 Ok((value, stalled_coroutine_goals))
245}
246
247pub(crate) fn deeply_normalize_for_diagnostics<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
249 infcx: &InferCtxt<'tcx>,
250 param_env: ty::ParamEnv<'tcx>,
251 t: T,
252) -> T {
253 t.fold_with(&mut DeeplyNormalizeForDiagnosticsFolder {
254 at: infcx.at(&ObligationCause::dummy(), param_env),
255 })
256}
257
258struct DeeplyNormalizeForDiagnosticsFolder<'a, 'tcx> {
259 at: At<'a, 'tcx>,
260}
261
262impl<'tcx> TypeFolder<TyCtxt<'tcx>> for DeeplyNormalizeForDiagnosticsFolder<'_, 'tcx> {
263 fn cx(&self) -> TyCtxt<'tcx> {
264 self.at.infcx.tcx
265 }
266
267 fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
268 let infcx = self.at.infcx;
269 let result: Result<_, Vec<ScrubbedTraitError<'tcx>>> = infcx.commit_if_ok(|_| {
270 deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals(
271 self.at,
272 Unnormalized::new_wip(ty),
273 ::alloc::vec::from_elem(None, ty.outer_exclusive_binder().as_usize())vec![None; ty.outer_exclusive_binder().as_usize()],
274 )
275 });
276 match result {
277 Ok((ty, _)) => ty,
278 Err(_) => ty.super_fold_with(self),
279 }
280 }
281
282 fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
283 let infcx = self.at.infcx;
284 let result: Result<_, Vec<ScrubbedTraitError<'tcx>>> = infcx.commit_if_ok(|_| {
285 deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals(
286 self.at,
287 Unnormalized::new_wip(ct),
288 ::alloc::vec::from_elem(None, ct.outer_exclusive_binder().as_usize())vec![None; ct.outer_exclusive_binder().as_usize()],
289 )
290 });
291 match result {
292 Ok((ct, _)) => ct,
293 Err(_) => ct.super_fold_with(self),
294 }
295 }
296}