]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_middle/src/ty/fold.rs
Merge commit '0cb0f7636851f9fcc57085cf80197a2ef6db098f' into clippyup
[rust.git] / compiler / rustc_middle / src / ty / fold.rs
1 //! A generalized traversal mechanism for complex data structures that contain
2 //! type information.
3 //!
4 //! There are two types of traversal.
5 //! - Folding. This is a modifying traversal. It consumes the data structure,
6 //!   producing a (possibly) modified version of it. Both fallible and
7 //!   infallible versions are available. The name is potentially
8 //!   confusing, because this traversal is more like `Iterator::map` than
9 //!   `Iterator::fold`.
10 //! - Visiting. This is a read-only traversal of the data structure.
11 //!
12 //! These traversals have limited flexibility. Only a small number of "types of
13 //! interest" within the complex data structures can receive custom
14 //! modification (when folding) or custom visitation (when visiting). These are
15 //! the ones containing the most important type-related information, such as
16 //! `Ty`, `Predicate`, `Region`, and `Const`.
17 //!
18 //! There are three traits involved in each traversal type.
19 //! - `TypeFoldable`. This is implemented once for many types. This includes
20 //!   both:
21 //!   - Types of interest, for which the the methods delegate to the
22 //!     folder/visitor.
23 //!   - All other types, including generic containers like `Vec` and `Option`.
24 //!     It defines a "skeleton" of how they should be traversed, for both
25 //!     folding and visiting.
26 //! - `TypeSuperFoldable`. This is implemented only for each type of interest,
27 //!   and defines the traversal "skeleton" for these types.
28 //! - `TypeFolder`/`FallibleTypeFolder` (for infallible/fallible folding
29 //!   traversals) or `TypeVisitor` (for visiting traversals). One of these is
30 //!   implemented for each folder/visitor. This defines how types of interest
31 //!   are folded/visited.
32 //!
33 //! This means each traversal is a mixture of (a) generic traversal operations,
34 //! and (b) custom fold/visit operations that are specific to the
35 //! folder/visitor.
36 //! - The `TypeFoldable` impls handle most of the traversal, and call into
37 //!   `TypeFolder`/`FallibleTypeFolder`/`TypeVisitor` when they encounter a
38 //!   type of interest.
39 //! - A `TypeFolder`/`FallibleTypeFolder`/`TypeVisitor` may call into another
40 //!   `TypeFoldable` impl, because some of the types of interest are recursive
41 //!   and can contain other types of interest.
42 //! - A `TypeFolder`/`FallibleTypeFolder`/`TypeVisitor` may also call into
43 //!   a `TypeSuperFoldable` impl, because each folder/visitor might provide
44 //!   custom handling only for some types of interest, or only for some
45 //!   variants of each type of interest, and then use default traversal for the
46 //!   remaining cases.
47 //!
48 //! For example, if you have `struct S(Ty, U)` where `S: TypeFoldable` and `U:
49 //! TypeFoldable`, and an instance `s = S(ty, u)`, it would be visited like so:
50 //! ```text
51 //! s.visit_with(visitor) calls
52 //! - ty.visit_with(visitor) calls
53 //!   - visitor.visit_ty(ty) may call
54 //!     - ty.super_visit_with(visitor)
55 //! - u.visit_with(visitor)
56 //! ```
57 use crate::mir;
58 use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags};
59 use rustc_errors::ErrorGuaranteed;
60 use rustc_hir::def_id::DefId;
61
62 use rustc_data_structures::fx::FxHashSet;
63 use rustc_data_structures::sso::SsoHashSet;
64 use std::collections::BTreeMap;
65 use std::fmt;
66 use std::ops::ControlFlow;
67
68 /// This trait is implemented for every type that can be folded/visited,
69 /// providing the skeleton of the traversal.
70 ///
71 /// To implement this conveniently, use the derive macro located in
72 /// `rustc_macros`.
73 pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
74     /// The entry point for folding. To fold a value `t` with a folder `f`
75     /// call: `t.try_fold_with(f)`.
76     ///
77     /// For most types, this just traverses the value, calling `try_fold_with`
78     /// on each field/element.
79     ///
80     /// For types of interest (such as `Ty`), the implementation of method
81     /// calls a folder method specifically for that type (such as
82     /// `F::try_fold_ty`). This is where control transfers from `TypeFoldable`
83     /// to `TypeFolder`.
84     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error>;
85
86     /// A convenient alternative to `try_fold_with` for use with infallible
87     /// folders. Do not override this method, to ensure coherence with
88     /// `try_fold_with`.
89     fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
90         self.try_fold_with(folder).into_ok()
91     }
92
93     /// The entry point for visiting. To visit a value `t` with a visitor `v`
94     /// call: `t.visit_with(v)`.
95     ///
96     /// For most types, this just traverses the value, calling `visit_with` on
97     /// each field/element.
98     ///
99     /// For types of interest (such as `Ty`), the implementation of this method
100     /// that calls a visitor method specifically for that type (such as
101     /// `V::visit_ty`). This is where control transfers from `TypeFoldable` to
102     /// `TypeVisitor`.
103     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
104
105     /// Returns `true` if `self` has any late-bound regions that are either
106     /// bound by `binder` or bound by some binder outside of `binder`.
107     /// If `binder` is `ty::INNERMOST`, this indicates whether
108     /// there are any late-bound regions that appear free.
109     fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
110         self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }).is_break()
111     }
112
113     /// Returns `true` if this `self` has any regions that escape `binder` (and
114     /// hence are not bound by it).
115     fn has_vars_bound_above(&self, binder: ty::DebruijnIndex) -> bool {
116         self.has_vars_bound_at_or_above(binder.shifted_in(1))
117     }
118
119     fn has_escaping_bound_vars(&self) -> bool {
120         self.has_vars_bound_at_or_above(ty::INNERMOST)
121     }
122
123     #[instrument(level = "trace")]
124     fn has_type_flags(&self, flags: TypeFlags) -> bool {
125         self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags)
126     }
127     fn has_projections(&self) -> bool {
128         self.has_type_flags(TypeFlags::HAS_PROJECTION)
129     }
130     fn has_opaque_types(&self) -> bool {
131         self.has_type_flags(TypeFlags::HAS_TY_OPAQUE)
132     }
133     fn references_error(&self) -> bool {
134         self.has_type_flags(TypeFlags::HAS_ERROR)
135     }
136     fn error_reported(&self) -> Option<ErrorGuaranteed> {
137         if self.references_error() {
138             Some(ErrorGuaranteed::unchecked_claim_error_was_emitted())
139         } else {
140             None
141         }
142     }
143     fn has_param_types_or_consts(&self) -> bool {
144         self.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_CT_PARAM)
145     }
146     fn has_infer_regions(&self) -> bool {
147         self.has_type_flags(TypeFlags::HAS_RE_INFER)
148     }
149     fn has_infer_types(&self) -> bool {
150         self.has_type_flags(TypeFlags::HAS_TY_INFER)
151     }
152     fn has_infer_types_or_consts(&self) -> bool {
153         self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_CT_INFER)
154     }
155     fn needs_infer(&self) -> bool {
156         self.has_type_flags(TypeFlags::NEEDS_INFER)
157     }
158     fn has_placeholders(&self) -> bool {
159         self.has_type_flags(
160             TypeFlags::HAS_RE_PLACEHOLDER
161                 | TypeFlags::HAS_TY_PLACEHOLDER
162                 | TypeFlags::HAS_CT_PLACEHOLDER,
163         )
164     }
165     fn needs_subst(&self) -> bool {
166         self.has_type_flags(TypeFlags::NEEDS_SUBST)
167     }
168     /// "Free" regions in this context means that it has any region
169     /// that is not (a) erased or (b) late-bound.
170     fn has_free_regions(&self) -> bool {
171         self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
172     }
173
174     fn has_erased_regions(&self) -> bool {
175         self.has_type_flags(TypeFlags::HAS_RE_ERASED)
176     }
177
178     /// True if there are any un-erased free regions.
179     fn has_erasable_regions(&self) -> bool {
180         self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
181     }
182
183     /// Indicates whether this value references only 'global'
184     /// generic parameters that are the same regardless of what fn we are
185     /// in. This is used for caching.
186     fn is_global(&self) -> bool {
187         !self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES)
188     }
189
190     /// True if there are any late-bound regions
191     fn has_late_bound_regions(&self) -> bool {
192         self.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND)
193     }
194
195     /// Indicates whether this value still has parameters/placeholders/inference variables
196     /// which could be replaced later, in a way that would change the results of `impl`
197     /// specialization.
198     fn still_further_specializable(&self) -> bool {
199         self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE)
200     }
201 }
202
203 // This trait is implemented for types of interest.
204 pub trait TypeSuperFoldable<'tcx>: TypeFoldable<'tcx> {
205     /// Provides a default fold for a type of interest. This should only be
206     /// called within `TypeFolder` methods, when a non-custom traversal is
207     /// desired for the value of the type of interest passed to that method.
208     /// For example, in `MyFolder::try_fold_ty(ty)`, it is valid to call
209     /// `ty.try_super_fold_with(self)`, but any other folding should be done
210     /// with `xyz.try_fold_with(self)`.
211     fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
212         self,
213         folder: &mut F,
214     ) -> Result<Self, F::Error>;
215
216     /// A convenient alternative to `try_super_fold_with` for use with
217     /// infallible folders. Do not override this method, to ensure coherence
218     /// with `try_super_fold_with`.
219     fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
220         self.try_super_fold_with(folder).into_ok()
221     }
222
223     /// Provides a default visit for a type of interest. This should only be
224     /// called within `TypeVisitor` methods, when a non-custom traversal is
225     /// desired for the value of the type of interest passed to that method.
226     /// For example, in `MyVisitor::visit_ty(ty)`, it is valid to call
227     /// `ty.super_visit_with(self)`, but any other visiting should be done
228     /// with `xyz.visit_with(self)`.
229     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
230 }
231
232 /// This trait is implemented for every infallible folding traversal. There is
233 /// a fold method defined for every type of interest. Each such method has a
234 /// default that does an "identity" fold. Implementations of these methods
235 /// often fall back to a `super_fold_with` method if the primary argument
236 /// doesn't satisfy a particular condition.
237 ///
238 /// A blanket implementation of [`FallibleTypeFolder`] will defer to
239 /// the infallible methods of this trait to ensure that the two APIs
240 /// are coherent.
241 pub trait TypeFolder<'tcx>: FallibleTypeFolder<'tcx, Error = !> {
242     fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
243
244     fn fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T>
245     where
246         T: TypeFoldable<'tcx>,
247     {
248         t.super_fold_with(self)
249     }
250
251     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
252         t.super_fold_with(self)
253     }
254
255     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
256         r.super_fold_with(self)
257     }
258
259     fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
260         c.super_fold_with(self)
261     }
262
263     fn fold_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ty::Unevaluated<'tcx> {
264         uv.super_fold_with(self)
265     }
266
267     fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
268         p.super_fold_with(self)
269     }
270
271     fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
272         bug!("most type folders should not be folding MIR datastructures: {:?}", c)
273     }
274 }
275
276 /// This trait is implemented for every folding traversal. There is a fold
277 /// method defined for every type of interest. Each such method has a default
278 /// that does an "identity" fold.
279 ///
280 /// A blanket implementation of this trait (that defers to the relevant
281 /// method of [`TypeFolder`]) is provided for all infallible folders in
282 /// order to ensure the two APIs are coherent.
283 pub trait FallibleTypeFolder<'tcx>: Sized {
284     type Error;
285
286     fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
287
288     fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error>
289     where
290         T: TypeFoldable<'tcx>,
291     {
292         t.try_super_fold_with(self)
293     }
294
295     fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
296         t.try_super_fold_with(self)
297     }
298
299     fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
300         r.try_super_fold_with(self)
301     }
302
303     fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
304         c.try_super_fold_with(self)
305     }
306
307     fn try_fold_unevaluated(
308         &mut self,
309         c: ty::Unevaluated<'tcx>,
310     ) -> Result<ty::Unevaluated<'tcx>, Self::Error> {
311         c.try_super_fold_with(self)
312     }
313
314     fn try_fold_predicate(
315         &mut self,
316         p: ty::Predicate<'tcx>,
317     ) -> Result<ty::Predicate<'tcx>, Self::Error> {
318         p.try_super_fold_with(self)
319     }
320
321     fn try_fold_mir_const(
322         &mut self,
323         c: mir::ConstantKind<'tcx>,
324     ) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
325         bug!("most type folders should not be folding MIR datastructures: {:?}", c)
326     }
327 }
328
329 // This blanket implementation of the fallible trait for infallible folders
330 // delegates to infallible methods to ensure coherence.
331 impl<'tcx, F> FallibleTypeFolder<'tcx> for F
332 where
333     F: TypeFolder<'tcx>,
334 {
335     type Error = !;
336
337     fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
338         TypeFolder::tcx(self)
339     }
340
341     fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, !>
342     where
343         T: TypeFoldable<'tcx>,
344     {
345         Ok(self.fold_binder(t))
346     }
347
348     fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, !> {
349         Ok(self.fold_ty(t))
350     }
351
352     fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, !> {
353         Ok(self.fold_region(r))
354     }
355
356     fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, !> {
357         Ok(self.fold_const(c))
358     }
359
360     fn try_fold_unevaluated(
361         &mut self,
362         c: ty::Unevaluated<'tcx>,
363     ) -> Result<ty::Unevaluated<'tcx>, !> {
364         Ok(self.fold_unevaluated(c))
365     }
366
367     fn try_fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> Result<ty::Predicate<'tcx>, !> {
368         Ok(self.fold_predicate(p))
369     }
370
371     fn try_fold_mir_const(
372         &mut self,
373         c: mir::ConstantKind<'tcx>,
374     ) -> Result<mir::ConstantKind<'tcx>, !> {
375         Ok(self.fold_mir_const(c))
376     }
377 }
378
379 /// This trait is implemented for every visiting traversal. There is a visit
380 /// method defined for every type of interest. Each such method has a default
381 /// that recurses into the type's fields in a non-custom fashion.
382 pub trait TypeVisitor<'tcx>: Sized {
383     type BreakTy = !;
384
385     fn visit_binder<T: TypeFoldable<'tcx>>(
386         &mut self,
387         t: &Binder<'tcx, T>,
388     ) -> ControlFlow<Self::BreakTy> {
389         t.super_visit_with(self)
390     }
391
392     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
393         t.super_visit_with(self)
394     }
395
396     fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
397         r.super_visit_with(self)
398     }
399
400     fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
401         c.super_visit_with(self)
402     }
403
404     fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
405         uv.super_visit_with(self)
406     }
407
408     fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
409         p.super_visit_with(self)
410     }
411
412     fn visit_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> ControlFlow<Self::BreakTy> {
413         c.super_visit_with(self)
414     }
415 }
416
417 ///////////////////////////////////////////////////////////////////////////
418 // Some sample folders
419
420 pub struct BottomUpFolder<'tcx, F, G, H>
421 where
422     F: FnMut(Ty<'tcx>) -> Ty<'tcx>,
423     G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>,
424     H: FnMut(ty::Const<'tcx>) -> ty::Const<'tcx>,
425 {
426     pub tcx: TyCtxt<'tcx>,
427     pub ty_op: F,
428     pub lt_op: G,
429     pub ct_op: H,
430 }
431
432 impl<'tcx, F, G, H> TypeFolder<'tcx> for BottomUpFolder<'tcx, F, G, H>
433 where
434     F: FnMut(Ty<'tcx>) -> Ty<'tcx>,
435     G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>,
436     H: FnMut(ty::Const<'tcx>) -> ty::Const<'tcx>,
437 {
438     fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
439         self.tcx
440     }
441
442     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
443         let t = ty.super_fold_with(self);
444         (self.ty_op)(t)
445     }
446
447     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
448         let r = r.super_fold_with(self);
449         (self.lt_op)(r)
450     }
451
452     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
453         let ct = ct.super_fold_with(self);
454         (self.ct_op)(ct)
455     }
456 }
457
458 ///////////////////////////////////////////////////////////////////////////
459 // Region folder
460
461 impl<'tcx> TyCtxt<'tcx> {
462     /// Folds the escaping and free regions in `value` using `f`, and
463     /// sets `skipped_regions` to true if any late-bound region was found
464     /// and skipped.
465     pub fn fold_regions<T>(
466         self,
467         value: T,
468         mut f: impl FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>,
469     ) -> T
470     where
471         T: TypeFoldable<'tcx>,
472     {
473         value.fold_with(&mut RegionFolder::new(self, &mut f))
474     }
475
476     /// Invoke `callback` on every region appearing free in `value`.
477     pub fn for_each_free_region(
478         self,
479         value: &impl TypeFoldable<'tcx>,
480         mut callback: impl FnMut(ty::Region<'tcx>),
481     ) {
482         self.any_free_region_meets(value, |r| {
483             callback(r);
484             false
485         });
486     }
487
488     /// Returns `true` if `callback` returns true for every region appearing free in `value`.
489     pub fn all_free_regions_meet(
490         self,
491         value: &impl TypeFoldable<'tcx>,
492         mut callback: impl FnMut(ty::Region<'tcx>) -> bool,
493     ) -> bool {
494         !self.any_free_region_meets(value, |r| !callback(r))
495     }
496
497     /// Returns `true` if `callback` returns true for some region appearing free in `value`.
498     pub fn any_free_region_meets(
499         self,
500         value: &impl TypeFoldable<'tcx>,
501         callback: impl FnMut(ty::Region<'tcx>) -> bool,
502     ) -> bool {
503         struct RegionVisitor<F> {
504             /// The index of a binder *just outside* the things we have
505             /// traversed. If we encounter a bound region bound by this
506             /// binder or one outer to it, it appears free. Example:
507             ///
508             /// ```ignore (illustrative)
509             ///       for<'a> fn(for<'b> fn(), T)
510             /// // ^          ^          ^     ^
511             /// // |          |          |     | here, would be shifted in 1
512             /// // |          |          | here, would be shifted in 2
513             /// // |          | here, would be `INNERMOST` shifted in by 1
514             /// // | here, initially, binder would be `INNERMOST`
515             /// ```
516             ///
517             /// You see that, initially, *any* bound value is free,
518             /// because we've not traversed any binders. As we pass
519             /// through a binder, we shift the `outer_index` by 1 to
520             /// account for the new binder that encloses us.
521             outer_index: ty::DebruijnIndex,
522             callback: F,
523         }
524
525         impl<'tcx, F> TypeVisitor<'tcx> for RegionVisitor<F>
526         where
527             F: FnMut(ty::Region<'tcx>) -> bool,
528         {
529             type BreakTy = ();
530
531             fn visit_binder<T: TypeFoldable<'tcx>>(
532                 &mut self,
533                 t: &Binder<'tcx, T>,
534             ) -> ControlFlow<Self::BreakTy> {
535                 self.outer_index.shift_in(1);
536                 let result = t.super_visit_with(self);
537                 self.outer_index.shift_out(1);
538                 result
539             }
540
541             fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
542                 match *r {
543                     ty::ReLateBound(debruijn, _) if debruijn < self.outer_index => {
544                         ControlFlow::CONTINUE
545                     }
546                     _ => {
547                         if (self.callback)(r) {
548                             ControlFlow::BREAK
549                         } else {
550                             ControlFlow::CONTINUE
551                         }
552                     }
553                 }
554             }
555
556             fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
557                 // We're only interested in types involving regions
558                 if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) {
559                     ty.super_visit_with(self)
560                 } else {
561                     ControlFlow::CONTINUE
562                 }
563             }
564         }
565
566         value.visit_with(&mut RegionVisitor { outer_index: ty::INNERMOST, callback }).is_break()
567     }
568 }
569
570 /// Folds over the substructure of a type, visiting its component
571 /// types and all regions that occur *free* within it.
572 ///
573 /// That is, `Ty` can contain function or method types that bind
574 /// regions at the call site (`ReLateBound`), and occurrences of
575 /// regions (aka "lifetimes") that are bound within a type are not
576 /// visited by this folder; only regions that occur free will be
577 /// visited by `fld_r`.
578
579 pub struct RegionFolder<'a, 'tcx> {
580     tcx: TyCtxt<'tcx>,
581
582     /// Stores the index of a binder *just outside* the stuff we have
583     /// visited.  So this begins as INNERMOST; when we pass through a
584     /// binder, it is incremented (via `shift_in`).
585     current_index: ty::DebruijnIndex,
586
587     /// Callback invokes for each free region. The `DebruijnIndex`
588     /// points to the binder *just outside* the ones we have passed
589     /// through.
590     fold_region_fn:
591         &'a mut (dyn FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx> + 'a),
592 }
593
594 impl<'a, 'tcx> RegionFolder<'a, 'tcx> {
595     #[inline]
596     pub fn new(
597         tcx: TyCtxt<'tcx>,
598         fold_region_fn: &'a mut dyn FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>,
599     ) -> RegionFolder<'a, 'tcx> {
600         RegionFolder { tcx, current_index: ty::INNERMOST, fold_region_fn }
601     }
602 }
603
604 impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
605     fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
606         self.tcx
607     }
608
609     fn fold_binder<T: TypeFoldable<'tcx>>(
610         &mut self,
611         t: ty::Binder<'tcx, T>,
612     ) -> ty::Binder<'tcx, T> {
613         self.current_index.shift_in(1);
614         let t = t.super_fold_with(self);
615         self.current_index.shift_out(1);
616         t
617     }
618
619     #[instrument(skip(self), level = "debug")]
620     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
621         match *r {
622             ty::ReLateBound(debruijn, _) if debruijn < self.current_index => {
623                 debug!(?self.current_index, "skipped bound region");
624                 r
625             }
626             _ => {
627                 debug!(?self.current_index, "folding free region");
628                 (self.fold_region_fn)(r, self.current_index)
629             }
630         }
631     }
632 }
633
634 ///////////////////////////////////////////////////////////////////////////
635 // Bound vars replacer
636
637 /// Replaces the escaping bound vars (late bound regions or bound types) in a type.
638 struct BoundVarReplacer<'a, 'tcx> {
639     tcx: TyCtxt<'tcx>,
640
641     /// As with `RegionFolder`, represents the index of a binder *just outside*
642     /// the ones we have visited.
643     current_index: ty::DebruijnIndex,
644
645     fld_r: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a),
646     fld_t: &'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a),
647     fld_c: &'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx> + 'a),
648 }
649
650 impl<'a, 'tcx> BoundVarReplacer<'a, 'tcx> {
651     fn new(
652         tcx: TyCtxt<'tcx>,
653         fld_r: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a),
654         fld_t: &'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a),
655         fld_c: &'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx> + 'a),
656     ) -> Self {
657         BoundVarReplacer { tcx, current_index: ty::INNERMOST, fld_r, fld_t, fld_c }
658     }
659 }
660
661 impl<'a, 'tcx> TypeFolder<'tcx> for BoundVarReplacer<'a, 'tcx> {
662     fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
663         self.tcx
664     }
665
666     fn fold_binder<T: TypeFoldable<'tcx>>(
667         &mut self,
668         t: ty::Binder<'tcx, T>,
669     ) -> ty::Binder<'tcx, T> {
670         self.current_index.shift_in(1);
671         let t = t.super_fold_with(self);
672         self.current_index.shift_out(1);
673         t
674     }
675
676     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
677         match *t.kind() {
678             ty::Bound(debruijn, bound_ty) if debruijn == self.current_index => {
679                 let ty = (self.fld_t)(bound_ty);
680                 ty::fold::shift_vars(self.tcx, ty, self.current_index.as_u32())
681             }
682             _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self),
683             _ => t,
684         }
685     }
686
687     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
688         match *r {
689             ty::ReLateBound(debruijn, br) if debruijn == self.current_index => {
690                 let region = (self.fld_r)(br);
691                 if let ty::ReLateBound(debruijn1, br) = *region {
692                     // If the callback returns a late-bound region,
693                     // that region should always use the INNERMOST
694                     // debruijn index. Then we adjust it to the
695                     // correct depth.
696                     assert_eq!(debruijn1, ty::INNERMOST);
697                     self.tcx.mk_region(ty::ReLateBound(debruijn, br))
698                 } else {
699                     region
700                 }
701             }
702             _ => r,
703         }
704     }
705
706     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
707         match ct.kind() {
708             ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => {
709                 let ct = (self.fld_c)(bound_const, ct.ty());
710                 ty::fold::shift_vars(self.tcx, ct, self.current_index.as_u32())
711             }
712             _ if ct.has_vars_bound_at_or_above(self.current_index) => ct.super_fold_with(self),
713             _ => ct,
714         }
715     }
716 }
717
718 impl<'tcx> TyCtxt<'tcx> {
719     /// Replaces all regions bound by the given `Binder` with the
720     /// results returned by the closure; the closure is expected to
721     /// return a free region (relative to this binder), and hence the
722     /// binder is removed in the return type. The closure is invoked
723     /// once for each unique `BoundRegionKind`; multiple references to the
724     /// same `BoundRegionKind` will reuse the previous result. A map is
725     /// returned at the end with each bound region and the free region
726     /// that replaced it.
727     ///
728     /// # Panics
729     ///
730     /// This method only replaces late bound regions. Any types or
731     /// constants bound by `value` will cause an ICE.
732     pub fn replace_late_bound_regions<T, F>(
733         self,
734         value: Binder<'tcx, T>,
735         mut fld_r: F,
736     ) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)
737     where
738         F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
739         T: TypeFoldable<'tcx>,
740     {
741         let mut region_map = BTreeMap::new();
742         let real_fld_r = |br: ty::BoundRegion| *region_map.entry(br).or_insert_with(|| fld_r(br));
743         let value = self.replace_late_bound_regions_uncached(value, real_fld_r);
744         (value, region_map)
745     }
746
747     pub fn replace_late_bound_regions_uncached<T, F>(
748         self,
749         value: Binder<'tcx, T>,
750         mut fld_r: F,
751     ) -> T
752     where
753         F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
754         T: TypeFoldable<'tcx>,
755     {
756         let mut fld_t = |b| bug!("unexpected bound ty in binder: {b:?}");
757         let mut fld_c = |b, ty| bug!("unexpected bound ct in binder: {b:?} {ty}");
758         let value = value.skip_binder();
759         if !value.has_escaping_bound_vars() {
760             value
761         } else {
762             let mut replacer = BoundVarReplacer::new(self, &mut fld_r, &mut fld_t, &mut fld_c);
763             value.fold_with(&mut replacer)
764         }
765     }
766
767     /// Replaces all escaping bound vars. The `fld_r` closure replaces escaping
768     /// bound regions; the `fld_t` closure replaces escaping bound types and the `fld_c`
769     /// closure replaces escaping bound consts.
770     pub fn replace_escaping_bound_vars_uncached<T, F, G, H>(
771         self,
772         value: T,
773         mut fld_r: F,
774         mut fld_t: G,
775         mut fld_c: H,
776     ) -> T
777     where
778         F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
779         G: FnMut(ty::BoundTy) -> Ty<'tcx>,
780         H: FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx>,
781         T: TypeFoldable<'tcx>,
782     {
783         if !value.has_escaping_bound_vars() {
784             value
785         } else {
786             let mut replacer = BoundVarReplacer::new(self, &mut fld_r, &mut fld_t, &mut fld_c);
787             value.fold_with(&mut replacer)
788         }
789     }
790
791     /// Replaces all types or regions bound by the given `Binder`. The `fld_r`
792     /// closure replaces bound regions, the `fld_t` closure replaces bound
793     /// types, and `fld_c` replaces bound constants.
794     pub fn replace_bound_vars_uncached<T, F, G, H>(
795         self,
796         value: Binder<'tcx, T>,
797         fld_r: F,
798         fld_t: G,
799         fld_c: H,
800     ) -> T
801     where
802         F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
803         G: FnMut(ty::BoundTy) -> Ty<'tcx>,
804         H: FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx>,
805         T: TypeFoldable<'tcx>,
806     {
807         self.replace_escaping_bound_vars_uncached(value.skip_binder(), fld_r, fld_t, fld_c)
808     }
809
810     /// Replaces any late-bound regions bound in `value` with
811     /// free variants attached to `all_outlive_scope`.
812     pub fn liberate_late_bound_regions<T>(
813         self,
814         all_outlive_scope: DefId,
815         value: ty::Binder<'tcx, T>,
816     ) -> T
817     where
818         T: TypeFoldable<'tcx>,
819     {
820         self.replace_late_bound_regions_uncached(value, |br| {
821             self.mk_region(ty::ReFree(ty::FreeRegion {
822                 scope: all_outlive_scope,
823                 bound_region: br.kind,
824             }))
825         })
826     }
827
828     pub fn shift_bound_var_indices<T>(self, bound_vars: usize, value: T) -> T
829     where
830         T: TypeFoldable<'tcx>,
831     {
832         self.replace_escaping_bound_vars_uncached(
833             value,
834             |r| {
835                 self.mk_region(ty::ReLateBound(
836                     ty::INNERMOST,
837                     ty::BoundRegion {
838                         var: ty::BoundVar::from_usize(r.var.as_usize() + bound_vars),
839                         kind: r.kind,
840                     },
841                 ))
842             },
843             |t| {
844                 self.mk_ty(ty::Bound(
845                     ty::INNERMOST,
846                     ty::BoundTy {
847                         var: ty::BoundVar::from_usize(t.var.as_usize() + bound_vars),
848                         kind: t.kind,
849                     },
850                 ))
851             },
852             |c, ty| {
853                 self.mk_const(ty::ConstS {
854                     kind: ty::ConstKind::Bound(
855                         ty::INNERMOST,
856                         ty::BoundVar::from_usize(c.as_usize() + bound_vars),
857                     ),
858                     ty,
859                 })
860             },
861         )
862     }
863
864     /// Returns a set of all late-bound regions that are constrained
865     /// by `value`, meaning that if we instantiate those LBR with
866     /// variables and equate `value` with something else, those
867     /// variables will also be equated.
868     pub fn collect_constrained_late_bound_regions<T>(
869         self,
870         value: &Binder<'tcx, T>,
871     ) -> FxHashSet<ty::BoundRegionKind>
872     where
873         T: TypeFoldable<'tcx>,
874     {
875         self.collect_late_bound_regions(value, true)
876     }
877
878     /// Returns a set of all late-bound regions that appear in `value` anywhere.
879     pub fn collect_referenced_late_bound_regions<T>(
880         self,
881         value: &Binder<'tcx, T>,
882     ) -> FxHashSet<ty::BoundRegionKind>
883     where
884         T: TypeFoldable<'tcx>,
885     {
886         self.collect_late_bound_regions(value, false)
887     }
888
889     fn collect_late_bound_regions<T>(
890         self,
891         value: &Binder<'tcx, T>,
892         just_constraint: bool,
893     ) -> FxHashSet<ty::BoundRegionKind>
894     where
895         T: TypeFoldable<'tcx>,
896     {
897         let mut collector = LateBoundRegionsCollector::new(just_constraint);
898         let result = value.as_ref().skip_binder().visit_with(&mut collector);
899         assert!(result.is_continue()); // should never have stopped early
900         collector.regions
901     }
902
903     /// Replaces any late-bound regions bound in `value` with `'erased`. Useful in codegen but also
904     /// method lookup and a few other places where precise region relationships are not required.
905     pub fn erase_late_bound_regions<T>(self, value: Binder<'tcx, T>) -> T
906     where
907         T: TypeFoldable<'tcx>,
908     {
909         self.replace_late_bound_regions(value, |_| self.lifetimes.re_erased).0
910     }
911
912     /// Rewrite any late-bound regions so that they are anonymous. Region numbers are
913     /// assigned starting at 0 and increasing monotonically in the order traversed
914     /// by the fold operation.
915     ///
916     /// The chief purpose of this function is to canonicalize regions so that two
917     /// `FnSig`s or `TraitRef`s which are equivalent up to region naming will become
918     /// structurally identical. For example, `for<'a, 'b> fn(&'a isize, &'b isize)` and
919     /// `for<'a, 'b> fn(&'b isize, &'a isize)` will become identical after anonymization.
920     pub fn anonymize_late_bound_regions<T>(self, sig: Binder<'tcx, T>) -> Binder<'tcx, T>
921     where
922         T: TypeFoldable<'tcx>,
923     {
924         let mut counter = 0;
925         let inner = self
926             .replace_late_bound_regions(sig, |_| {
927                 let br = ty::BoundRegion {
928                     var: ty::BoundVar::from_u32(counter),
929                     kind: ty::BrAnon(counter),
930                 };
931                 let r = self.mk_region(ty::ReLateBound(ty::INNERMOST, br));
932                 counter += 1;
933                 r
934             })
935             .0;
936         let bound_vars = self.mk_bound_variable_kinds(
937             (0..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i))),
938         );
939         Binder::bind_with_vars(inner, bound_vars)
940     }
941 }
942
943 pub struct ValidateBoundVars<'tcx> {
944     bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
945     binder_index: ty::DebruijnIndex,
946     // We may encounter the same variable at different levels of binding, so
947     // this can't just be `Ty`
948     visited: SsoHashSet<(ty::DebruijnIndex, Ty<'tcx>)>,
949 }
950
951 impl<'tcx> ValidateBoundVars<'tcx> {
952     pub fn new(bound_vars: &'tcx ty::List<ty::BoundVariableKind>) -> Self {
953         ValidateBoundVars {
954             bound_vars,
955             binder_index: ty::INNERMOST,
956             visited: SsoHashSet::default(),
957         }
958     }
959 }
960
961 impl<'tcx> TypeVisitor<'tcx> for ValidateBoundVars<'tcx> {
962     type BreakTy = ();
963
964     fn visit_binder<T: TypeFoldable<'tcx>>(
965         &mut self,
966         t: &Binder<'tcx, T>,
967     ) -> ControlFlow<Self::BreakTy> {
968         self.binder_index.shift_in(1);
969         let result = t.super_visit_with(self);
970         self.binder_index.shift_out(1);
971         result
972     }
973
974     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
975         if t.outer_exclusive_binder() < self.binder_index
976             || !self.visited.insert((self.binder_index, t))
977         {
978             return ControlFlow::BREAK;
979         }
980         match *t.kind() {
981             ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
982                 if self.bound_vars.len() <= bound_ty.var.as_usize() {
983                     bug!("Not enough bound vars: {:?} not found in {:?}", t, self.bound_vars);
984                 }
985                 let list_var = self.bound_vars[bound_ty.var.as_usize()];
986                 match list_var {
987                     ty::BoundVariableKind::Ty(kind) => {
988                         if kind != bound_ty.kind {
989                             bug!(
990                                 "Mismatched type kinds: {:?} doesn't var in list {:?}",
991                                 bound_ty.kind,
992                                 list_var
993                             );
994                         }
995                     }
996                     _ => {
997                         bug!("Mismatched bound variable kinds! Expected type, found {:?}", list_var)
998                     }
999                 }
1000             }
1001
1002             _ => (),
1003         };
1004
1005         t.super_visit_with(self)
1006     }
1007
1008     fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
1009         match *r {
1010             ty::ReLateBound(index, br) if index == self.binder_index => {
1011                 if self.bound_vars.len() <= br.var.as_usize() {
1012                     bug!("Not enough bound vars: {:?} not found in {:?}", br, self.bound_vars);
1013                 }
1014                 let list_var = self.bound_vars[br.var.as_usize()];
1015                 match list_var {
1016                     ty::BoundVariableKind::Region(kind) => {
1017                         if kind != br.kind {
1018                             bug!(
1019                                 "Mismatched region kinds: {:?} doesn't match var ({:?}) in list ({:?})",
1020                                 br.kind,
1021                                 list_var,
1022                                 self.bound_vars
1023                             );
1024                         }
1025                     }
1026                     _ => bug!(
1027                         "Mismatched bound variable kinds! Expected region, found {:?}",
1028                         list_var
1029                     ),
1030                 }
1031             }
1032
1033             _ => (),
1034         };
1035
1036         r.super_visit_with(self)
1037     }
1038 }
1039
1040 ///////////////////////////////////////////////////////////////////////////
1041 // Shifter
1042 //
1043 // Shifts the De Bruijn indices on all escaping bound vars by a
1044 // fixed amount. Useful in substitution or when otherwise introducing
1045 // a binding level that is not intended to capture the existing bound
1046 // vars. See comment on `shift_vars_through_binders` method in
1047 // `subst.rs` for more details.
1048
1049 struct Shifter<'tcx> {
1050     tcx: TyCtxt<'tcx>,
1051     current_index: ty::DebruijnIndex,
1052     amount: u32,
1053 }
1054
1055 impl<'tcx> Shifter<'tcx> {
1056     pub fn new(tcx: TyCtxt<'tcx>, amount: u32) -> Self {
1057         Shifter { tcx, current_index: ty::INNERMOST, amount }
1058     }
1059 }
1060
1061 impl<'tcx> TypeFolder<'tcx> for Shifter<'tcx> {
1062     fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
1063         self.tcx
1064     }
1065
1066     fn fold_binder<T: TypeFoldable<'tcx>>(
1067         &mut self,
1068         t: ty::Binder<'tcx, T>,
1069     ) -> ty::Binder<'tcx, T> {
1070         self.current_index.shift_in(1);
1071         let t = t.super_fold_with(self);
1072         self.current_index.shift_out(1);
1073         t
1074     }
1075
1076     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
1077         match *r {
1078             ty::ReLateBound(debruijn, br) => {
1079                 if self.amount == 0 || debruijn < self.current_index {
1080                     r
1081                 } else {
1082                     let debruijn = debruijn.shifted_in(self.amount);
1083                     let shifted = ty::ReLateBound(debruijn, br);
1084                     self.tcx.mk_region(shifted)
1085                 }
1086             }
1087             _ => r,
1088         }
1089     }
1090
1091     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
1092         match *ty.kind() {
1093             ty::Bound(debruijn, bound_ty) => {
1094                 if self.amount == 0 || debruijn < self.current_index {
1095                     ty
1096                 } else {
1097                     let debruijn = debruijn.shifted_in(self.amount);
1098                     self.tcx.mk_ty(ty::Bound(debruijn, bound_ty))
1099                 }
1100             }
1101
1102             _ => ty.super_fold_with(self),
1103         }
1104     }
1105
1106     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
1107         if let ty::ConstKind::Bound(debruijn, bound_ct) = ct.kind() {
1108             if self.amount == 0 || debruijn < self.current_index {
1109                 ct
1110             } else {
1111                 let debruijn = debruijn.shifted_in(self.amount);
1112                 self.tcx.mk_const(ty::ConstS {
1113                     kind: ty::ConstKind::Bound(debruijn, bound_ct),
1114                     ty: ct.ty(),
1115                 })
1116             }
1117         } else {
1118             ct.super_fold_with(self)
1119         }
1120     }
1121 }
1122
1123 pub fn shift_region<'tcx>(
1124     tcx: TyCtxt<'tcx>,
1125     region: ty::Region<'tcx>,
1126     amount: u32,
1127 ) -> ty::Region<'tcx> {
1128     match *region {
1129         ty::ReLateBound(debruijn, br) if amount > 0 => {
1130             tcx.mk_region(ty::ReLateBound(debruijn.shifted_in(amount), br))
1131         }
1132         _ => region,
1133     }
1134 }
1135
1136 pub fn shift_vars<'tcx, T>(tcx: TyCtxt<'tcx>, value: T, amount: u32) -> T
1137 where
1138     T: TypeFoldable<'tcx>,
1139 {
1140     debug!("shift_vars(value={:?}, amount={})", value, amount);
1141
1142     value.fold_with(&mut Shifter::new(tcx, amount))
1143 }
1144
1145 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
1146 struct FoundEscapingVars;
1147
1148 /// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a
1149 /// bound region or a bound type.
1150 ///
1151 /// So, for example, consider a type like the following, which has two binders:
1152 ///
1153 ///    for<'a> fn(x: for<'b> fn(&'a isize, &'b isize))
1154 ///    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ outer scope
1155 ///                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~  inner scope
1156 ///
1157 /// This type has *bound regions* (`'a`, `'b`), but it does not have escaping regions, because the
1158 /// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner
1159 /// fn type*, that type has an escaping region: `'a`.
1160 ///
1161 /// Note that what I'm calling an "escaping var" is often just called a "free var". However,
1162 /// we already use the term "free var". It refers to the regions or types that we use to represent
1163 /// bound regions or type params on a fn definition while we are type checking its body.
1164 ///
1165 /// To clarify, conceptually there is no particular difference between
1166 /// an "escaping" var and a "free" var. However, there is a big
1167 /// difference in practice. Basically, when "entering" a binding
1168 /// level, one is generally required to do some sort of processing to
1169 /// a bound var, such as replacing it with a fresh/placeholder
1170 /// var, or making an entry in the environment to represent the
1171 /// scope to which it is attached, etc. An escaping var represents
1172 /// a bound var for which this processing has not yet been done.
1173 struct HasEscapingVarsVisitor {
1174     /// Anything bound by `outer_index` or "above" is escaping.
1175     outer_index: ty::DebruijnIndex,
1176 }
1177
1178 impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor {
1179     type BreakTy = FoundEscapingVars;
1180
1181     fn visit_binder<T: TypeFoldable<'tcx>>(
1182         &mut self,
1183         t: &Binder<'tcx, T>,
1184     ) -> ControlFlow<Self::BreakTy> {
1185         self.outer_index.shift_in(1);
1186         let result = t.super_visit_with(self);
1187         self.outer_index.shift_out(1);
1188         result
1189     }
1190
1191     #[inline]
1192     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
1193         // If the outer-exclusive-binder is *strictly greater* than
1194         // `outer_index`, that means that `t` contains some content
1195         // bound at `outer_index` or above (because
1196         // `outer_exclusive_binder` is always 1 higher than the
1197         // content in `t`). Therefore, `t` has some escaping vars.
1198         if t.outer_exclusive_binder() > self.outer_index {
1199             ControlFlow::Break(FoundEscapingVars)
1200         } else {
1201             ControlFlow::CONTINUE
1202         }
1203     }
1204
1205     #[inline]
1206     fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
1207         // If the region is bound by `outer_index` or anything outside
1208         // of outer index, then it escapes the binders we have
1209         // visited.
1210         if r.bound_at_or_above_binder(self.outer_index) {
1211             ControlFlow::Break(FoundEscapingVars)
1212         } else {
1213             ControlFlow::CONTINUE
1214         }
1215     }
1216
1217     fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
1218         // we don't have a `visit_infer_const` callback, so we have to
1219         // hook in here to catch this case (annoying...), but
1220         // otherwise we do want to remember to visit the rest of the
1221         // const, as it has types/regions embedded in a lot of other
1222         // places.
1223         match ct.kind() {
1224             ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => {
1225                 ControlFlow::Break(FoundEscapingVars)
1226             }
1227             _ => ct.super_visit_with(self),
1228         }
1229     }
1230
1231     #[inline]
1232     fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
1233         if predicate.outer_exclusive_binder() > self.outer_index {
1234             ControlFlow::Break(FoundEscapingVars)
1235         } else {
1236             ControlFlow::CONTINUE
1237         }
1238     }
1239 }
1240
1241 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
1242 struct FoundFlags;
1243
1244 // FIXME: Optimize for checking for infer flags
1245 struct HasTypeFlagsVisitor {
1246     flags: ty::TypeFlags,
1247 }
1248
1249 impl std::fmt::Debug for HasTypeFlagsVisitor {
1250     fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1251         self.flags.fmt(fmt)
1252     }
1253 }
1254
1255 impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
1256     type BreakTy = FoundFlags;
1257
1258     #[inline]
1259     #[instrument(skip(self), level = "trace")]
1260     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
1261         let flags = t.flags();
1262         trace!(t.flags=?t.flags());
1263         if flags.intersects(self.flags) {
1264             ControlFlow::Break(FoundFlags)
1265         } else {
1266             ControlFlow::CONTINUE
1267         }
1268     }
1269
1270     #[inline]
1271     #[instrument(skip(self), level = "trace")]
1272     fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
1273         let flags = r.type_flags();
1274         trace!(r.flags=?flags);
1275         if flags.intersects(self.flags) {
1276             ControlFlow::Break(FoundFlags)
1277         } else {
1278             ControlFlow::CONTINUE
1279         }
1280     }
1281
1282     #[inline]
1283     #[instrument(level = "trace")]
1284     fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
1285         let flags = FlagComputation::for_const(c);
1286         trace!(r.flags=?flags);
1287         if flags.intersects(self.flags) {
1288             ControlFlow::Break(FoundFlags)
1289         } else {
1290             ControlFlow::CONTINUE
1291         }
1292     }
1293
1294     #[inline]
1295     #[instrument(level = "trace")]
1296     fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
1297         let flags = FlagComputation::for_unevaluated_const(uv);
1298         trace!(r.flags=?flags);
1299         if flags.intersects(self.flags) {
1300             ControlFlow::Break(FoundFlags)
1301         } else {
1302             ControlFlow::CONTINUE
1303         }
1304     }
1305
1306     #[inline]
1307     #[instrument(level = "trace")]
1308     fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
1309         debug!(
1310             "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}",
1311             predicate,
1312             predicate.flags(),
1313             self.flags
1314         );
1315         if predicate.flags().intersects(self.flags) {
1316             ControlFlow::Break(FoundFlags)
1317         } else {
1318             ControlFlow::CONTINUE
1319         }
1320     }
1321 }
1322
1323 /// Collects all the late-bound regions at the innermost binding level
1324 /// into a hash set.
1325 struct LateBoundRegionsCollector {
1326     current_index: ty::DebruijnIndex,
1327     regions: FxHashSet<ty::BoundRegionKind>,
1328
1329     /// `true` if we only want regions that are known to be
1330     /// "constrained" when you equate this type with another type. In
1331     /// particular, if you have e.g., `&'a u32` and `&'b u32`, equating
1332     /// them constraints `'a == 'b`. But if you have `<&'a u32 as
1333     /// Trait>::Foo` and `<&'b u32 as Trait>::Foo`, normalizing those
1334     /// types may mean that `'a` and `'b` don't appear in the results,
1335     /// so they are not considered *constrained*.
1336     just_constrained: bool,
1337 }
1338
1339 impl LateBoundRegionsCollector {
1340     fn new(just_constrained: bool) -> Self {
1341         LateBoundRegionsCollector {
1342             current_index: ty::INNERMOST,
1343             regions: Default::default(),
1344             just_constrained,
1345         }
1346     }
1347 }
1348
1349 impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
1350     fn visit_binder<T: TypeFoldable<'tcx>>(
1351         &mut self,
1352         t: &Binder<'tcx, T>,
1353     ) -> ControlFlow<Self::BreakTy> {
1354         self.current_index.shift_in(1);
1355         let result = t.super_visit_with(self);
1356         self.current_index.shift_out(1);
1357         result
1358     }
1359
1360     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
1361         // if we are only looking for "constrained" region, we have to
1362         // ignore the inputs to a projection, as they may not appear
1363         // in the normalized form
1364         if self.just_constrained {
1365             if let ty::Projection(..) = t.kind() {
1366                 return ControlFlow::CONTINUE;
1367             }
1368         }
1369
1370         t.super_visit_with(self)
1371     }
1372
1373     fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
1374         // if we are only looking for "constrained" region, we have to
1375         // ignore the inputs of an unevaluated const, as they may not appear
1376         // in the normalized form
1377         if self.just_constrained {
1378             if let ty::ConstKind::Unevaluated(..) = c.kind() {
1379                 return ControlFlow::CONTINUE;
1380             }
1381         }
1382
1383         c.super_visit_with(self)
1384     }
1385
1386     fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
1387         if let ty::ReLateBound(debruijn, br) = *r {
1388             if debruijn == self.current_index {
1389                 self.regions.insert(br.kind);
1390             }
1391         }
1392         ControlFlow::CONTINUE
1393     }
1394 }
1395
1396 /// Finds the max universe present
1397 pub struct MaxUniverse {
1398     max_universe: ty::UniverseIndex,
1399 }
1400
1401 impl MaxUniverse {
1402     pub fn new() -> Self {
1403         MaxUniverse { max_universe: ty::UniverseIndex::ROOT }
1404     }
1405
1406     pub fn max_universe(self) -> ty::UniverseIndex {
1407         self.max_universe
1408     }
1409 }
1410
1411 impl<'tcx> TypeVisitor<'tcx> for MaxUniverse {
1412     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
1413         if let ty::Placeholder(placeholder) = t.kind() {
1414             self.max_universe = ty::UniverseIndex::from_u32(
1415                 self.max_universe.as_u32().max(placeholder.universe.as_u32()),
1416             );
1417         }
1418
1419         t.super_visit_with(self)
1420     }
1421
1422     fn visit_const(&mut self, c: ty::consts::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
1423         if let ty::ConstKind::Placeholder(placeholder) = c.kind() {
1424             self.max_universe = ty::UniverseIndex::from_u32(
1425                 self.max_universe.as_u32().max(placeholder.universe.as_u32()),
1426             );
1427         }
1428
1429         c.super_visit_with(self)
1430     }
1431
1432     fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
1433         if let ty::RePlaceholder(placeholder) = *r {
1434             self.max_universe = ty::UniverseIndex::from_u32(
1435                 self.max_universe.as_u32().max(placeholder.universe.as_u32()),
1436             );
1437         }
1438
1439         ControlFlow::CONTINUE
1440     }
1441 }