]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_trait_selection/src/traits/query/normalize.rs
af1029521726a41ccad1ff821ca19e00350c13bd
[rust.git] / compiler / rustc_trait_selection / src / traits / query / normalize.rs
1 //! Code for the 'normalization' query. This consists of a wrapper
2 //! which folds deeply, invoking the underlying
3 //! `normalize_projection_ty` query when it encounters projections.
4
5 use crate::infer::at::At;
6 use crate::infer::canonical::OriginalQueryValues;
7 use crate::infer::{InferCtxt, InferOk};
8 use crate::traits::error_reporting::TypeErrCtxtExt;
9 use crate::traits::project::{needs_normalization, BoundVarReplacer, PlaceholderReplacer};
10 use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
11 use rustc_data_structures::sso::SsoHashMap;
12 use rustc_data_structures::stack::ensure_sufficient_stack;
13 use rustc_infer::traits::Normalized;
14 use rustc_middle::mir;
15 use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
16 use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable};
17 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor};
18
19 use std::ops::ControlFlow;
20
21 use super::NoSolution;
22
23 pub use rustc_middle::traits::query::NormalizationResult;
24
25 pub trait AtExt<'tcx> {
26     fn normalize<T>(&self, value: T) -> Result<Normalized<'tcx, T>, NoSolution>
27     where
28         T: TypeFoldable<'tcx>;
29 }
30
31 impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
32     /// Normalize `value` in the context of the inference context,
33     /// yielding a resulting type, or an error if `value` cannot be
34     /// normalized. If you don't care about regions, you should prefer
35     /// `normalize_erasing_regions`, which is more efficient.
36     ///
37     /// If the normalization succeeds and is unambiguous, returns back
38     /// the normalized value along with various outlives relations (in
39     /// the form of obligations that must be discharged).
40     ///
41     /// N.B., this will *eventually* be the main means of
42     /// normalizing, but for now should be used only when we actually
43     /// know that normalization will succeed, since error reporting
44     /// and other details are still "under development".
45     fn normalize<T>(&self, value: T) -> Result<Normalized<'tcx, T>, NoSolution>
46     where
47         T: TypeFoldable<'tcx>,
48     {
49         debug!(
50             "normalize::<{}>(value={:?}, param_env={:?}, cause={:?})",
51             std::any::type_name::<T>(),
52             value,
53             self.param_env,
54             self.cause,
55         );
56         if !needs_normalization(&value, self.param_env.reveal()) {
57             return Ok(Normalized { value, obligations: vec![] });
58         }
59
60         let mut normalizer = QueryNormalizer {
61             infcx: self.infcx,
62             cause: self.cause,
63             param_env: self.param_env,
64             obligations: vec![],
65             cache: SsoHashMap::new(),
66             anon_depth: 0,
67             universes: vec![],
68         };
69
70         // This is actually a consequence by the way `normalize_erasing_regions` works currently.
71         // Because it needs to call the `normalize_generic_arg_after_erasing_regions`, it folds
72         // through tys and consts in a `TypeFoldable`. Importantly, it skips binders, leaving us
73         // with trying to normalize with escaping bound vars.
74         //
75         // Here, we just add the universes that we *would* have created had we passed through the binders.
76         //
77         // We *could* replace escaping bound vars eagerly here, but it doesn't seem really necessary.
78         // The rest of the code is already set up to be lazy about replacing bound vars,
79         // and only when we actually have to normalize.
80         if value.has_escaping_bound_vars() {
81             let mut max_visitor =
82                 MaxEscapingBoundVarVisitor { outer_index: ty::INNERMOST, escaping: 0 };
83             value.visit_with(&mut max_visitor);
84             if max_visitor.escaping > 0 {
85                 normalizer.universes.extend((0..max_visitor.escaping).map(|_| None));
86             }
87         }
88         let result = value.try_fold_with(&mut normalizer);
89         info!(
90             "normalize::<{}>: result={:?} with {} obligations",
91             std::any::type_name::<T>(),
92             result,
93             normalizer.obligations.len(),
94         );
95         debug!(
96             "normalize::<{}>: obligations={:?}",
97             std::any::type_name::<T>(),
98             normalizer.obligations,
99         );
100         result.map(|value| Normalized { value, obligations: normalizer.obligations })
101     }
102 }
103
104 // Visitor to find the maximum escaping bound var
105 struct MaxEscapingBoundVarVisitor {
106     // The index which would count as escaping
107     outer_index: ty::DebruijnIndex,
108     escaping: usize,
109 }
110
111 impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor {
112     fn visit_binder<T: TypeVisitable<'tcx>>(
113         &mut self,
114         t: &ty::Binder<'tcx, T>,
115     ) -> ControlFlow<Self::BreakTy> {
116         self.outer_index.shift_in(1);
117         let result = t.super_visit_with(self);
118         self.outer_index.shift_out(1);
119         result
120     }
121
122     #[inline]
123     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
124         if t.outer_exclusive_binder() > self.outer_index {
125             self.escaping = self
126                 .escaping
127                 .max(t.outer_exclusive_binder().as_usize() - self.outer_index.as_usize());
128         }
129         ControlFlow::CONTINUE
130     }
131
132     #[inline]
133     fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
134         match *r {
135             ty::ReLateBound(debruijn, _) if debruijn > self.outer_index => {
136                 self.escaping =
137                     self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize());
138             }
139             _ => {}
140         }
141         ControlFlow::CONTINUE
142     }
143
144     fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
145         match ct.kind() {
146             ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => {
147                 self.escaping =
148                     self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize());
149                 ControlFlow::CONTINUE
150             }
151             _ => ct.super_visit_with(self),
152         }
153     }
154 }
155
156 struct QueryNormalizer<'cx, 'tcx> {
157     infcx: &'cx InferCtxt<'tcx>,
158     cause: &'cx ObligationCause<'tcx>,
159     param_env: ty::ParamEnv<'tcx>,
160     obligations: Vec<PredicateObligation<'tcx>>,
161     cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>,
162     anon_depth: usize,
163     universes: Vec<Option<ty::UniverseIndex>>,
164 }
165
166 impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
167     type Error = NoSolution;
168
169     fn tcx<'c>(&'c self) -> TyCtxt<'tcx> {
170         self.infcx.tcx
171     }
172
173     fn try_fold_binder<T: TypeFoldable<'tcx>>(
174         &mut self,
175         t: ty::Binder<'tcx, T>,
176     ) -> Result<ty::Binder<'tcx, T>, Self::Error> {
177         self.universes.push(None);
178         let t = t.try_super_fold_with(self);
179         self.universes.pop();
180         t
181     }
182
183     #[instrument(level = "debug", skip(self))]
184     fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
185         if !needs_normalization(&ty, self.param_env.reveal()) {
186             return Ok(ty);
187         }
188
189         if let Some(ty) = self.cache.get(&ty) {
190             return Ok(*ty);
191         }
192
193         // See note in `rustc_trait_selection::traits::project` about why we
194         // wait to fold the substs.
195
196         // Wrap this in a closure so we don't accidentally return from the outer function
197         let res = (|| match *ty.kind() {
198             // This is really important. While we *can* handle this, this has
199             // severe performance implications for large opaque types with
200             // late-bound regions. See `issue-88862` benchmark.
201             ty::Opaque(def_id, substs) => {
202                 // Only normalize `impl Trait` outside of type inference, usually in codegen.
203                 match self.param_env.reveal() {
204                     Reveal::UserFacing => ty.try_super_fold_with(self),
205
206                     Reveal::All => {
207                         let substs = substs.try_fold_with(self)?;
208                         let recursion_limit = self.tcx().recursion_limit();
209                         if !recursion_limit.value_within_limit(self.anon_depth) {
210                             let obligation = Obligation::with_depth(
211                                 self.cause.clone(),
212                                 recursion_limit.0,
213                                 self.param_env,
214                                 ty,
215                             );
216                             self.infcx.err_ctxt().report_overflow_error(&obligation, true);
217                         }
218
219                         let generic_ty = self.tcx().bound_type_of(def_id);
220                         let concrete_ty = generic_ty.subst(self.tcx(), substs);
221                         self.anon_depth += 1;
222                         if concrete_ty == ty {
223                             bug!(
224                                 "infinite recursion generic_ty: {:#?}, substs: {:#?}, \
225                                  concrete_ty: {:#?}, ty: {:#?}",
226                                 generic_ty,
227                                 substs,
228                                 concrete_ty,
229                                 ty
230                             );
231                         }
232                         let folded_ty = ensure_sufficient_stack(|| self.try_fold_ty(concrete_ty));
233                         self.anon_depth -= 1;
234                         folded_ty
235                     }
236                 }
237             }
238
239             ty::Projection(data) if !data.has_escaping_bound_vars() => {
240                 // This branch is just an optimization: when we don't have escaping bound vars,
241                 // we don't need to replace them with placeholders (see branch below).
242
243                 let tcx = self.infcx.tcx;
244                 let data = data.try_fold_with(self)?;
245
246                 let mut orig_values = OriginalQueryValues::default();
247                 // HACK(matthewjasper) `'static` is special-cased in selection,
248                 // so we cannot canonicalize it.
249                 let c_data = self
250                     .infcx
251                     .canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
252                 debug!("QueryNormalizer: c_data = {:#?}", c_data);
253                 debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
254                 let result = tcx.normalize_projection_ty(c_data)?;
255                 // We don't expect ambiguity.
256                 if result.is_ambiguous() {
257                     bug!("unexpected ambiguity: {:?} {:?}", c_data, result);
258                 }
259                 let InferOk { value: result, obligations } =
260                     self.infcx.instantiate_query_response_and_region_obligations(
261                         self.cause,
262                         self.param_env,
263                         &orig_values,
264                         result,
265                     )?;
266                 debug!("QueryNormalizer: result = {:#?}", result);
267                 debug!("QueryNormalizer: obligations = {:#?}", obligations);
268                 self.obligations.extend(obligations);
269
270                 let res = result.normalized_ty;
271                 // `tcx.normalize_projection_ty` may normalize to a type that still has
272                 // unevaluated consts, so keep normalizing here if that's the case.
273                 if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) {
274                     Ok(res.try_super_fold_with(self)?)
275                 } else {
276                     Ok(res)
277                 }
278             }
279
280             ty::Projection(data) => {
281                 // See note in `rustc_trait_selection::traits::project`
282
283                 let tcx = self.infcx.tcx;
284                 let infcx = self.infcx;
285                 let (data, mapped_regions, mapped_types, mapped_consts) =
286                     BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
287                 let data = data.try_fold_with(self)?;
288
289                 let mut orig_values = OriginalQueryValues::default();
290                 // HACK(matthewjasper) `'static` is special-cased in selection,
291                 // so we cannot canonicalize it.
292                 let c_data = self
293                     .infcx
294                     .canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
295                 debug!("QueryNormalizer: c_data = {:#?}", c_data);
296                 debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
297                 let result = tcx.normalize_projection_ty(c_data)?;
298                 // We don't expect ambiguity.
299                 if result.is_ambiguous() {
300                     bug!("unexpected ambiguity: {:?} {:?}", c_data, result);
301                 }
302                 let InferOk { value: result, obligations } =
303                     self.infcx.instantiate_query_response_and_region_obligations(
304                         self.cause,
305                         self.param_env,
306                         &orig_values,
307                         result,
308                     )?;
309                 debug!("QueryNormalizer: result = {:#?}", result);
310                 debug!("QueryNormalizer: obligations = {:#?}", obligations);
311                 self.obligations.extend(obligations);
312                 let res = PlaceholderReplacer::replace_placeholders(
313                     infcx,
314                     mapped_regions,
315                     mapped_types,
316                     mapped_consts,
317                     &self.universes,
318                     result.normalized_ty,
319                 );
320                 // `tcx.normalize_projection_ty` may normalize to a type that still has
321                 // unevaluated consts, so keep normalizing here if that's the case.
322                 if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) {
323                     Ok(res.try_super_fold_with(self)?)
324                 } else {
325                     Ok(res)
326                 }
327             }
328
329             _ => ty.try_super_fold_with(self),
330         })()?;
331
332         self.cache.insert(ty, res);
333         Ok(res)
334     }
335
336     fn try_fold_const(
337         &mut self,
338         constant: ty::Const<'tcx>,
339     ) -> Result<ty::Const<'tcx>, Self::Error> {
340         let constant = constant.try_super_fold_with(self)?;
341         debug!(?constant, ?self.param_env);
342         Ok(crate::traits::project::with_replaced_escaping_bound_vars(
343             self.infcx,
344             &mut self.universes,
345             constant,
346             |constant| constant.eval(self.infcx.tcx, self.param_env),
347         ))
348     }
349
350     fn try_fold_mir_const(
351         &mut self,
352         constant: mir::ConstantKind<'tcx>,
353     ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
354         constant.try_super_fold_with(self)
355     }
356
357     #[inline]
358     fn try_fold_predicate(
359         &mut self,
360         p: ty::Predicate<'tcx>,
361     ) -> Result<ty::Predicate<'tcx>, Self::Error> {
362         if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) {
363             p.try_super_fold_with(self)
364         } else {
365             Ok(p)
366         }
367     }
368 }