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;
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 let original_value = value.clone();
46 let mut folder =
47 NormalizationFolder::new(infcx, universes.clone(), Default::default(), |alias_term| {
48 let delegate = <&SolverDelegate<'tcx>>::from(infcx);
49 let infer_term =
50 delegate.next_term_var_of_kind(alias_term.to_term(infcx.tcx), at.cause.span);
51 let predicate =
52 ty::ProjectionPredicate { projection_term: alias_term, term: infer_term };
53 let goal = Goal::new(infcx.tcx, at.param_env, predicate);
54 let result = delegate.evaluate_root_goal(goal, at.cause.span, None)?;
55 let normalized = infcx.resolve_vars_if_possible(infer_term);
56 let stalled_goal = match result.certainty {
57 Certainty::Yes => None,
58 Certainty::Maybe { .. } => Some(infcx.resolve_vars_if_possible(result.goal)),
59 };
60 Ok((normalized, stalled_goal))
61 });
62 if let Ok(value) = value.try_fold_with(&mut folder) {
63 let obligations = folder
64 .stalled_goals()
65 .into_iter()
66 .map(|goal| {
67 Obligation::new(infcx.tcx, at.cause.clone(), goal.param_env, goal.predicate)
68 })
69 .collect();
70 Normalized { value, obligations }
71 } else {
72 let mut replacer = ReplaceAliasWithInfer { at, obligations: Default::default(), universes };
73 let value = original_value.fold_with(&mut replacer);
74 Normalized { value, obligations: replacer.obligations }
75 }
76}
77
78struct ReplaceAliasWithInfer<'me, 'tcx> {
79 at: At<'me, 'tcx>,
80 obligations: PredicateObligations<'tcx>,
81 universes: Vec<Option<UniverseIndex>>,
82}
83
84impl<'me, 'tcx> ReplaceAliasWithInfer<'me, 'tcx> {
85 fn term_to_infer(&mut self, alias_term: ty::AliasTerm<'tcx>) -> ty::Term<'tcx> {
86 let infcx = self.at.infcx;
87 let infer_term =
88 infcx.next_term_var_of_kind(alias_term.to_term(infcx.tcx), self.at.cause.span);
89 let obligation = Obligation::new(
90 infcx.tcx,
91 self.at.cause.clone(),
92 self.at.param_env,
93 ty::ProjectionPredicate { projection_term: alias_term, term: infer_term },
94 );
95 self.obligations.push(obligation);
96 infer_term
97 }
98}
99
100impl<'me, 'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceAliasWithInfer<'me, 'tcx> {
101 fn cx(&self) -> TyCtxt<'tcx> {
102 self.at.infcx.tcx
103 }
104
105 fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
106 &mut self,
107 t: Binder<'tcx, T>,
108 ) -> Binder<'tcx, T> {
109 self.universes.push(None);
110 let t = t.super_fold_with(self);
111 self.universes.pop();
112 t
113 }
114
115 fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
116 if !ty.has_aliases() {
117 return ty;
118 }
119
120 let ty = ty.super_fold_with(self);
121 let ty::Alias(alias) = *ty.kind() else { return ty };
122
123 if ty.has_escaping_bound_vars() {
124 let (replaced, ..) =
125 BoundVarReplacer::replace_bound_vars(self.at.infcx, &mut self.universes, alias);
126 let _ = self.term_to_infer(replaced.into());
127 ty
128 } else {
129 self.term_to_infer(alias.into()).expect_type()
130 }
131 }
132
133 fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
134 if !ct.has_aliases() {
135 return ct;
136 }
137
138 let ct = ct.super_fold_with(self);
139 let ty::ConstKind::Unevaluated(uv) = ct.kind() else { return ct };
140
141 if ct.has_escaping_bound_vars() {
142 let (replaced, ..) =
143 BoundVarReplacer::replace_bound_vars(self.at.infcx, &mut self.universes, uv);
144 let _ = self.term_to_infer(replaced.into());
145 ct
146 } else {
147 self.term_to_infer(uv.into()).expect_const()
148 }
149 }
150}
151
152pub fn deeply_normalize<'tcx, T, E>(
155 at: At<'_, 'tcx>,
156 value: Unnormalized<'tcx, T>,
157) -> Result<T, Vec<E>>
158where
159 T: TypeFoldable<TyCtxt<'tcx>>,
160 E: FromSolverError<'tcx, NextSolverError<'tcx>>,
161{
162 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());
163 deeply_normalize_with_skipped_universes(at, value, ::alloc::vec::Vec::new()vec![])
164}
165
166pub fn deeply_normalize_with_skipped_universes<'tcx, T, E>(
173 at: At<'_, 'tcx>,
174 value: Unnormalized<'tcx, T>,
175 universes: Vec<Option<UniverseIndex>>,
176) -> Result<T, Vec<E>>
177where
178 T: TypeFoldable<TyCtxt<'tcx>>,
179 E: FromSolverError<'tcx, NextSolverError<'tcx>>,
180{
181 let (value, coroutine_goals) =
182 deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals(
183 at, value, universes,
184 )?;
185 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![]);
186
187 Ok(value)
188}
189
190pub fn deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals<'tcx, T, E>(
200 at: At<'_, 'tcx>,
201 value: Unnormalized<'tcx, T>,
202 universes: Vec<Option<UniverseIndex>>,
203) -> Result<(T, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), Vec<E>>
204where
205 T: TypeFoldable<TyCtxt<'tcx>>,
206 E: FromSolverError<'tcx, NextSolverError<'tcx>>,
207{
208 let Normalized { value, obligations } = normalize_with_universes(at, value, universes);
209
210 let mut fulfill_cx = FulfillmentCtxt::new(at.infcx);
211 for pred in obligations {
212 fulfill_cx.register_predicate_obligation(at.infcx, pred);
213 }
214
215 let errors = fulfill_cx.try_evaluate_obligations(at.infcx);
216 if !errors.is_empty() {
217 return Err(errors);
218 }
219
220 let stalled_coroutine_goals = fulfill_cx
221 .drain_stalled_obligations_for_coroutines(at.infcx)
222 .into_iter()
223 .map(|obl| obl.as_goal())
224 .collect();
225
226 let errors = fulfill_cx.collect_remaining_errors(at.infcx);
227 if !errors.is_empty() {
228 return Err(errors);
229 }
230
231 Ok((value, stalled_coroutine_goals))
232}
233
234pub(crate) fn deeply_normalize_for_diagnostics<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
236 infcx: &InferCtxt<'tcx>,
237 param_env: ty::ParamEnv<'tcx>,
238 t: T,
239) -> T {
240 t.fold_with(&mut DeeplyNormalizeForDiagnosticsFolder {
241 at: infcx.at(&ObligationCause::dummy(), param_env),
242 })
243}
244
245struct DeeplyNormalizeForDiagnosticsFolder<'a, 'tcx> {
246 at: At<'a, 'tcx>,
247}
248
249impl<'tcx> TypeFolder<TyCtxt<'tcx>> for DeeplyNormalizeForDiagnosticsFolder<'_, 'tcx> {
250 fn cx(&self) -> TyCtxt<'tcx> {
251 self.at.infcx.tcx
252 }
253
254 fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
255 let infcx = self.at.infcx;
256 let result: Result<_, Vec<ScrubbedTraitError<'tcx>>> = infcx.commit_if_ok(|_| {
257 deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals(
258 self.at,
259 Unnormalized::new_wip(ty),
260 ::alloc::vec::from_elem(None, ty.outer_exclusive_binder().as_usize())vec![None; ty.outer_exclusive_binder().as_usize()],
261 )
262 });
263 match result {
264 Ok((ty, _)) => ty,
265 Err(_) => ty.super_fold_with(self),
266 }
267 }
268
269 fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
270 let infcx = self.at.infcx;
271 let result: Result<_, Vec<ScrubbedTraitError<'tcx>>> = infcx.commit_if_ok(|_| {
272 deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals(
273 self.at,
274 Unnormalized::new_wip(ct),
275 ::alloc::vec::from_elem(None, ct.outer_exclusive_binder().as_usize())vec![None; ct.outer_exclusive_binder().as_usize()],
276 )
277 });
278 match result {
279 Ok((ct, _)) => ct,
280 Err(_) => ct.super_fold_with(self),
281 }
282 }
283}