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, PredicateObligation, PredicateObligations,
6 TraitEngine, TraitErrors,
7};
8use rustc_middle::traits::ObligationCause;
9use rustc_middle::ty::{
10 self, Binder, Flags, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
11 UniverseIndex, Unnormalized,
12};
13use rustc_next_trait_solver::normalize::{NormalizationFolder, NormalizationWasAmbiguous};
14use rustc_next_trait_solver::solve::SolverDelegateEvalExt;
15use thin_vec::{ThinVec, thin_vec};
16
17use super::{FulfillmentCtxt, NextSolverError};
18use crate::solve::{Certainty, SolverDelegate};
19use crate::traits::{BoundVarReplacer, ScrubbedTraitError};
20
21pub fn normalize<'tcx, T>(at: At<'_, 'tcx>, value: Unnormalized<'tcx, T>) -> Normalized<'tcx, T>
23where
24 T: TypeFoldable<TyCtxt<'tcx>>,
25{
26 match normalize_with_universes(at, value.clone(), ::alloc::vec::Vec::new()vec![]) {
27 Ok(normalized) => normalized,
28 Err(_) => {
29 let mut replacer =
30 ReplaceAliasWithInfer { at, obligations: Default::default(), universes: ::alloc::vec::Vec::new()vec![] };
31 let value = at.infcx.deeply_resolve_ignoring_regions(value.skip_normalization());
32 let value = value.fold_with(&mut replacer);
33 Normalized { value, obligations: replacer.obligations }
34 }
35 }
36}
37
38fn normalize_with_universes<'tcx, T>(
46 at: At<'_, 'tcx>,
47 value: Unnormalized<'tcx, T>,
48 universes: Vec<Option<UniverseIndex>>,
49) -> Result<Normalized<'tcx, T>, PredicateObligation<'tcx>>
50where
51 T: TypeFoldable<TyCtxt<'tcx>>,
52{
53 let infcx = at.infcx;
54 let value = value.skip_normalization();
55 let value = infcx.deeply_resolve_ignoring_regions(value);
56
57 if !infcx.tcx.renormalize_rigid_aliases() && !value.has_non_rigid_aliases() {
58 return Ok(Normalized { value, obligations: Default::default() });
59 }
60
61 let mut stalled_goals = ::alloc::vec::Vec::new()vec![];
62 let mut folder = NormalizationFolder::new(infcx, universes, |alias_term| {
63 let delegate = <&SolverDelegate<'tcx>>::from(infcx);
64 let infer_term = delegate.next_term_var_of_alias_kind(alias_term, at.cause.span);
65 let predicate = ty::ProjectionClause { projection_term: alias_term, term: infer_term };
66 let goal = Goal::new(infcx.tcx, at.param_env, predicate);
67 let result = match delegate.evaluate_root_goal(goal, at.cause.span, None) {
68 Ok(result) => result,
69 Err(_) => {
70 return Err(Obligation::new(
71 infcx.tcx,
72 at.cause.clone(),
73 goal.param_env,
74 goal.predicate,
75 ));
76 }
77 };
78 let normalized = infcx.deeply_resolve_ignoring_regions(infer_term);
79 let normalization_was_ambiguous = match result.certainty {
80 Certainty::Yes => NormalizationWasAmbiguous::No,
81 Certainty::Maybe { .. } => {
82 stalled_goals.push(result.goal);
83 NormalizationWasAmbiguous::Yes
84 }
85 };
86 Ok((normalized, normalization_was_ambiguous))
87 });
88 let value = value.try_fold_with(&mut folder)?;
89 let obligations = stalled_goals
90 .into_iter()
91 .map(|goal| Obligation::new(infcx.tcx, at.cause.clone(), goal.param_env, goal.predicate))
92 .collect();
93 Ok(Normalized { value, obligations })
94}
95
96struct ReplaceAliasWithInfer<'me, 'tcx> {
97 at: At<'me, 'tcx>,
98 obligations: PredicateObligations<'tcx>,
99 universes: Vec<Option<UniverseIndex>>,
100}
101
102impl<'me, 'tcx> ReplaceAliasWithInfer<'me, 'tcx> {
103 fn term_to_infer(&mut self, alias_term: ty::AliasTerm<'tcx>) -> ty::Term<'tcx> {
104 let infcx = self.at.infcx;
105 let infer_term = infcx.next_term_var_of_alias_kind(alias_term, self.at.cause.span);
106 let obligation = Obligation::new(
107 infcx.tcx,
108 self.at.cause.clone(),
109 self.at.param_env,
110 ty::ProjectionClause { projection_term: alias_term, term: infer_term },
111 );
112 self.obligations.push(obligation);
113 infer_term
114 }
115}
116
117impl<'me, 'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceAliasWithInfer<'me, 'tcx> {
118 fn cx(&self) -> TyCtxt<'tcx> {
119 self.at.infcx.tcx
120 }
121
122 fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
123 &mut self,
124 t: Binder<'tcx, T>,
125 ) -> Binder<'tcx, T> {
126 self.universes.push(None);
127 let t = t.super_fold_with(self);
128 self.universes.pop();
129 t
130 }
131
132 fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
133 if !self.cx().renormalize_rigid_aliases() && !ty.has_non_rigid_aliases() {
134 return ty;
135 }
136
137 let ty = ty.super_fold_with(self);
138 let ty::Alias(orig_is_rigid, alias) = *ty.kind() else { return ty };
139 if !self.cx().renormalize_rigid_aliases() && orig_is_rigid == ty::IsRigid::Yes {
140 return ty;
141 }
142
143 if ty.has_escaping_bound_vars() {
144 let (replaced, ..) =
145 BoundVarReplacer::replace_bound_vars(self.at.infcx, &mut self.universes, alias);
146 let _ = self.term_to_infer(replaced.into());
149 ty
150 } else {
151 self.term_to_infer(alias.into()).expect_type()
152 }
153 }
154
155 fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
156 if !self.cx().renormalize_rigid_aliases() && !ct.has_non_rigid_aliases() {
157 return ct;
158 }
159
160 let ct = ct.super_fold_with(self);
161 let ty::ConstKind::Alias(orig_is_rigid, alias_const) = ct.kind() else { return ct };
162 if !self.cx().renormalize_rigid_aliases() && orig_is_rigid == ty::IsRigid::Yes {
163 return ct;
164 }
165
166 if ct.has_escaping_bound_vars() {
167 let (replaced, ..) = BoundVarReplacer::replace_bound_vars(
168 self.at.infcx,
169 &mut self.universes,
170 alias_const,
171 );
172 let _ = self.term_to_infer(replaced.into());
175 ct
176 } else {
177 self.term_to_infer(alias_const.into()).expect_const()
178 }
179 }
180}
181
182pub fn deeply_normalize<'tcx, T, E>(
185 at: At<'_, 'tcx>,
186 value: Unnormalized<'tcx, T>,
187) -> Result<T, ThinVec<E>>
188where
189 T: TypeFoldable<TyCtxt<'tcx>>,
190 E: FromSolverError<'tcx, NextSolverError<'tcx>>,
191{
192 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());
193 deeply_normalize_with_skipped_universes(at, value, ::alloc::vec::Vec::new()vec![])
194}
195
196pub fn deeply_normalize_with_skipped_universes<'tcx, T, E>(
203 at: At<'_, 'tcx>,
204 value: Unnormalized<'tcx, T>,
205 universes: Vec<Option<UniverseIndex>>,
206) -> Result<T, ThinVec<E>>
207where
208 T: TypeFoldable<TyCtxt<'tcx>>,
209 E: FromSolverError<'tcx, NextSolverError<'tcx>>,
210{
211 let (value, coroutine_goals) =
212 deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals(
213 at, value, universes,
214 )?;
215 {
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![]);
216
217 Ok(value)
218}
219
220pub fn deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals<'tcx, T, E>(
230 at: At<'_, 'tcx>,
231 value: Unnormalized<'tcx, T>,
232 universes: Vec<Option<UniverseIndex>>,
233) -> Result<(T, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), ThinVec<E>>
234where
235 T: TypeFoldable<TyCtxt<'tcx>>,
236 E: FromSolverError<'tcx, NextSolverError<'tcx>>,
237{
238 let Normalized { value, obligations } = normalize_with_universes(at, value, universes)
239 .map_err(|obligation| {
240 {
let len = [()].len();
let mut vec = ::thin_vec::ThinVec::with_capacity(len);
vec.push(E::from_solver_error(at.infcx,
NextSolverError::TrueError(obligation)));
vec
}thin_vec![E::from_solver_error(at.infcx, NextSolverError::TrueError(obligation))]
241 })?;
242
243 let mut fulfill_cx = FulfillmentCtxt::new(at.infcx);
244 for pred in obligations {
245 fulfill_cx.register_predicate_obligation(at.infcx, pred);
246 }
247
248 let errors = fulfill_cx.try_evaluate_obligations(at.infcx);
249 if let TraitErrors::HasErrors(errors) = errors {
250 return Err(errors);
251 }
252
253 let stalled_coroutine_goals = fulfill_cx
254 .drain_stalled_obligations_for_coroutines(at.infcx)
255 .into_iter()
256 .map(|obl| obl.as_goal())
257 .collect();
258
259 let errors = fulfill_cx.collect_remaining_errors(at.infcx);
260 if let TraitErrors::HasErrors(errors) = errors {
261 return Err(errors);
262 }
263
264 Ok((value, stalled_coroutine_goals))
265}
266
267pub(crate) fn deeply_normalize_for_diagnostics<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
269 infcx: &InferCtxt<'tcx>,
270 param_env: ty::ParamEnv<'tcx>,
271 t: T,
272) -> T {
273 t.fold_with(&mut DeeplyNormalizeForDiagnosticsFolder {
274 at: infcx.at(&ObligationCause::dummy(), param_env),
275 })
276}
277
278struct DeeplyNormalizeForDiagnosticsFolder<'a, 'tcx> {
279 at: At<'a, 'tcx>,
280}
281
282impl<'tcx> TypeFolder<TyCtxt<'tcx>> for DeeplyNormalizeForDiagnosticsFolder<'_, 'tcx> {
283 fn cx(&self) -> TyCtxt<'tcx> {
284 self.at.infcx.tcx
285 }
286
287 fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
288 let infcx = self.at.infcx;
289 let result: Result<_, ThinVec<ScrubbedTraitError<'tcx>>> = infcx.commit_if_ok(|_| {
290 deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals(
291 self.at,
292 Unnormalized::new_wip(ty),
293 ::alloc::vec::from_elem(None, ty.outer_exclusive_binder().as_usize())vec![None; ty.outer_exclusive_binder().as_usize()],
294 )
295 });
296 match result {
297 Ok((ty, _)) => ty,
298 Err(_) => ty.super_fold_with(self),
299 }
300 }
301
302 fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
303 let infcx = self.at.infcx;
304 let result: Result<_, ThinVec<ScrubbedTraitError<'tcx>>> = infcx.commit_if_ok(|_| {
305 deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals(
306 self.at,
307 Unnormalized::new_wip(ct),
308 ::alloc::vec::from_elem(None, ct.outer_exclusive_binder().as_usize())vec![None; ct.outer_exclusive_binder().as_usize()],
309 )
310 });
311 match result {
312 Ok((ct, _)) => ct,
313 Err(_) => ct.super_fold_with(self),
314 }
315 }
316}