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