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