• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags};
2 use rustc_errors::ErrorGuaranteed;
3 
4 use rustc_data_structures::fx::FxHashSet;
5 use rustc_data_structures::sso::SsoHashSet;
6 use std::ops::ControlFlow;
7 
8 pub use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
9 
10 pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> {
11     /// Returns `true` if `self` has any late-bound regions that are either
12     /// bound by `binder` or bound by some binder outside of `binder`.
13     /// If `binder` is `ty::INNERMOST`, this indicates whether
14     /// there are any late-bound regions that appear free.
has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool15     fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
16         self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }).is_break()
17     }
18 
19     /// Returns `true` if this type has any regions that escape `binder` (and
20     /// hence are not bound by it).
has_vars_bound_above(&self, binder: ty::DebruijnIndex) -> bool21     fn has_vars_bound_above(&self, binder: ty::DebruijnIndex) -> bool {
22         self.has_vars_bound_at_or_above(binder.shifted_in(1))
23     }
24 
25     /// Return `true` if this type has regions that are not a part of the type.
26     /// For example, `for<'a> fn(&'a i32)` return `false`, while `fn(&'a i32)`
27     /// would return `true`. The latter can occur when traversing through the
28     /// former.
29     ///
30     /// See [`HasEscapingVarsVisitor`] for more information.
has_escaping_bound_vars(&self) -> bool31     fn has_escaping_bound_vars(&self) -> bool {
32         self.has_vars_bound_at_or_above(ty::INNERMOST)
33     }
34 
has_type_flags(&self, flags: TypeFlags) -> bool35     fn has_type_flags(&self, flags: TypeFlags) -> bool {
36         // N.B. Even though this uses a visitor, the visitor does not actually
37         //      recurse through the whole `TypeVisitable` implementor type.
38         //
39         //      Instead it stops on the first "level", visiting types, regions,
40         //      consts and predicates just fetches their type flags.
41         //
42         //      Thus this is a lot faster than it might seem and should be
43         //      optimized to a simple field access.
44         let res =
45             self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags);
46         trace!(?self, ?flags, ?res, "has_type_flags");
47         res
48     }
has_projections(&self) -> bool49     fn has_projections(&self) -> bool {
50         self.has_type_flags(TypeFlags::HAS_PROJECTION)
51     }
has_inherent_projections(&self) -> bool52     fn has_inherent_projections(&self) -> bool {
53         self.has_type_flags(TypeFlags::HAS_TY_INHERENT)
54     }
has_opaque_types(&self) -> bool55     fn has_opaque_types(&self) -> bool {
56         self.has_type_flags(TypeFlags::HAS_TY_OPAQUE)
57     }
has_generators(&self) -> bool58     fn has_generators(&self) -> bool {
59         self.has_type_flags(TypeFlags::HAS_TY_GENERATOR)
60     }
references_error(&self) -> bool61     fn references_error(&self) -> bool {
62         self.has_type_flags(TypeFlags::HAS_ERROR)
63     }
error_reported(&self) -> Result<(), ErrorGuaranteed>64     fn error_reported(&self) -> Result<(), ErrorGuaranteed> {
65         if self.references_error() {
66             if let Some(reported) = ty::tls::with(|tcx| tcx.sess.is_compilation_going_to_fail()) {
67                 Err(reported)
68             } else {
69                 bug!("expect tcx.sess.is_compilation_going_to_fail return `Some`");
70             }
71         } else {
72             Ok(())
73         }
74     }
has_non_region_param(&self) -> bool75     fn has_non_region_param(&self) -> bool {
76         self.has_type_flags(TypeFlags::HAS_PARAM - TypeFlags::HAS_RE_PARAM)
77     }
has_infer_regions(&self) -> bool78     fn has_infer_regions(&self) -> bool {
79         self.has_type_flags(TypeFlags::HAS_RE_INFER)
80     }
has_infer_types(&self) -> bool81     fn has_infer_types(&self) -> bool {
82         self.has_type_flags(TypeFlags::HAS_TY_INFER)
83     }
has_non_region_infer(&self) -> bool84     fn has_non_region_infer(&self) -> bool {
85         self.has_type_flags(TypeFlags::HAS_INFER - TypeFlags::HAS_RE_INFER)
86     }
has_infer(&self) -> bool87     fn has_infer(&self) -> bool {
88         self.has_type_flags(TypeFlags::HAS_INFER)
89     }
has_placeholders(&self) -> bool90     fn has_placeholders(&self) -> bool {
91         self.has_type_flags(
92             TypeFlags::HAS_RE_PLACEHOLDER
93                 | TypeFlags::HAS_TY_PLACEHOLDER
94                 | TypeFlags::HAS_CT_PLACEHOLDER,
95         )
96     }
has_non_region_placeholders(&self) -> bool97     fn has_non_region_placeholders(&self) -> bool {
98         self.has_type_flags(TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER)
99     }
has_param(&self) -> bool100     fn has_param(&self) -> bool {
101         self.has_type_flags(TypeFlags::HAS_PARAM)
102     }
103     /// "Free" regions in this context means that it has any region
104     /// that is not (a) erased or (b) late-bound.
has_free_regions(&self) -> bool105     fn has_free_regions(&self) -> bool {
106         self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
107     }
108 
has_erased_regions(&self) -> bool109     fn has_erased_regions(&self) -> bool {
110         self.has_type_flags(TypeFlags::HAS_RE_ERASED)
111     }
112 
113     /// True if there are any un-erased free regions.
has_erasable_regions(&self) -> bool114     fn has_erasable_regions(&self) -> bool {
115         self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
116     }
117 
118     /// Indicates whether this value references only 'global'
119     /// generic parameters that are the same regardless of what fn we are
120     /// in. This is used for caching.
is_global(&self) -> bool121     fn is_global(&self) -> bool {
122         !self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES)
123     }
124 
125     /// True if there are any late-bound regions
has_late_bound_regions(&self) -> bool126     fn has_late_bound_regions(&self) -> bool {
127         self.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND)
128     }
129     /// True if there are any late-bound non-region variables
has_non_region_late_bound(&self) -> bool130     fn has_non_region_late_bound(&self) -> bool {
131         self.has_type_flags(TypeFlags::HAS_LATE_BOUND - TypeFlags::HAS_RE_LATE_BOUND)
132     }
133     /// True if there are any late-bound variables
has_late_bound_vars(&self) -> bool134     fn has_late_bound_vars(&self) -> bool {
135         self.has_type_flags(TypeFlags::HAS_LATE_BOUND)
136     }
137 
138     /// Indicates whether this value still has parameters/placeholders/inference variables
139     /// which could be replaced later, in a way that would change the results of `impl`
140     /// specialization.
still_further_specializable(&self) -> bool141     fn still_further_specializable(&self) -> bool {
142         self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE)
143     }
144 }
145 
146 impl<'tcx, T: TypeVisitable<TyCtxt<'tcx>>> TypeVisitableExt<'tcx> for T {}
147 
148 ///////////////////////////////////////////////////////////////////////////
149 // Region folder
150 
151 impl<'tcx> TyCtxt<'tcx> {
152     /// Invoke `callback` on every region appearing free in `value`.
for_each_free_region( self, value: &impl TypeVisitable<TyCtxt<'tcx>>, mut callback: impl FnMut(ty::Region<'tcx>), )153     pub fn for_each_free_region(
154         self,
155         value: &impl TypeVisitable<TyCtxt<'tcx>>,
156         mut callback: impl FnMut(ty::Region<'tcx>),
157     ) {
158         self.any_free_region_meets(value, |r| {
159             callback(r);
160             false
161         });
162     }
163 
164     /// Returns `true` if `callback` returns true for every region appearing free in `value`.
all_free_regions_meet( self, value: &impl TypeVisitable<TyCtxt<'tcx>>, mut callback: impl FnMut(ty::Region<'tcx>) -> bool, ) -> bool165     pub fn all_free_regions_meet(
166         self,
167         value: &impl TypeVisitable<TyCtxt<'tcx>>,
168         mut callback: impl FnMut(ty::Region<'tcx>) -> bool,
169     ) -> bool {
170         !self.any_free_region_meets(value, |r| !callback(r))
171     }
172 
173     /// Returns `true` if `callback` returns true for some region appearing free in `value`.
any_free_region_meets( self, value: &impl TypeVisitable<TyCtxt<'tcx>>, callback: impl FnMut(ty::Region<'tcx>) -> bool, ) -> bool174     pub fn any_free_region_meets(
175         self,
176         value: &impl TypeVisitable<TyCtxt<'tcx>>,
177         callback: impl FnMut(ty::Region<'tcx>) -> bool,
178     ) -> bool {
179         struct RegionVisitor<F> {
180             /// The index of a binder *just outside* the things we have
181             /// traversed. If we encounter a bound region bound by this
182             /// binder or one outer to it, it appears free. Example:
183             ///
184             /// ```ignore (illustrative)
185             ///       for<'a> fn(for<'b> fn(), T)
186             /// // ^          ^          ^     ^
187             /// // |          |          |     | here, would be shifted in 1
188             /// // |          |          | here, would be shifted in 2
189             /// // |          | here, would be `INNERMOST` shifted in by 1
190             /// // | here, initially, binder would be `INNERMOST`
191             /// ```
192             ///
193             /// You see that, initially, *any* bound value is free,
194             /// because we've not traversed any binders. As we pass
195             /// through a binder, we shift the `outer_index` by 1 to
196             /// account for the new binder that encloses us.
197             outer_index: ty::DebruijnIndex,
198             callback: F,
199         }
200 
201         impl<'tcx, F> TypeVisitor<TyCtxt<'tcx>> for RegionVisitor<F>
202         where
203             F: FnMut(ty::Region<'tcx>) -> bool,
204         {
205             type BreakTy = ();
206 
207             fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
208                 &mut self,
209                 t: &Binder<'tcx, T>,
210             ) -> ControlFlow<Self::BreakTy> {
211                 self.outer_index.shift_in(1);
212                 let result = t.super_visit_with(self);
213                 self.outer_index.shift_out(1);
214                 result
215             }
216 
217             fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
218                 match *r {
219                     ty::ReLateBound(debruijn, _) if debruijn < self.outer_index => {
220                         ControlFlow::Continue(())
221                     }
222                     _ => {
223                         if (self.callback)(r) {
224                             ControlFlow::Break(())
225                         } else {
226                             ControlFlow::Continue(())
227                         }
228                     }
229                 }
230             }
231 
232             fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
233                 // We're only interested in types involving regions
234                 if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) {
235                     ty.super_visit_with(self)
236                 } else {
237                     ControlFlow::Continue(())
238                 }
239             }
240         }
241 
242         value.visit_with(&mut RegionVisitor { outer_index: ty::INNERMOST, callback }).is_break()
243     }
244 
245     /// Returns a set of all late-bound regions that are constrained
246     /// by `value`, meaning that if we instantiate those LBR with
247     /// variables and equate `value` with something else, those
248     /// variables will also be equated.
collect_constrained_late_bound_regions<T>( self, value: &Binder<'tcx, T>, ) -> FxHashSet<ty::BoundRegionKind> where T: TypeVisitable<TyCtxt<'tcx>>,249     pub fn collect_constrained_late_bound_regions<T>(
250         self,
251         value: &Binder<'tcx, T>,
252     ) -> FxHashSet<ty::BoundRegionKind>
253     where
254         T: TypeVisitable<TyCtxt<'tcx>>,
255     {
256         self.collect_late_bound_regions(value, true)
257     }
258 
259     /// Returns a set of all late-bound regions that appear in `value` anywhere.
collect_referenced_late_bound_regions<T>( self, value: &Binder<'tcx, T>, ) -> FxHashSet<ty::BoundRegionKind> where T: TypeVisitable<TyCtxt<'tcx>>,260     pub fn collect_referenced_late_bound_regions<T>(
261         self,
262         value: &Binder<'tcx, T>,
263     ) -> FxHashSet<ty::BoundRegionKind>
264     where
265         T: TypeVisitable<TyCtxt<'tcx>>,
266     {
267         self.collect_late_bound_regions(value, false)
268     }
269 
collect_late_bound_regions<T>( self, value: &Binder<'tcx, T>, just_constraint: bool, ) -> FxHashSet<ty::BoundRegionKind> where T: TypeVisitable<TyCtxt<'tcx>>,270     fn collect_late_bound_regions<T>(
271         self,
272         value: &Binder<'tcx, T>,
273         just_constraint: bool,
274     ) -> FxHashSet<ty::BoundRegionKind>
275     where
276         T: TypeVisitable<TyCtxt<'tcx>>,
277     {
278         let mut collector = LateBoundRegionsCollector::new(just_constraint);
279         let result = value.as_ref().skip_binder().visit_with(&mut collector);
280         assert!(result.is_continue()); // should never have stopped early
281         collector.regions
282     }
283 }
284 
285 pub struct ValidateBoundVars<'tcx> {
286     bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
287     binder_index: ty::DebruijnIndex,
288     // We may encounter the same variable at different levels of binding, so
289     // this can't just be `Ty`
290     visited: SsoHashSet<(ty::DebruijnIndex, Ty<'tcx>)>,
291 }
292 
293 impl<'tcx> ValidateBoundVars<'tcx> {
new(bound_vars: &'tcx ty::List<ty::BoundVariableKind>) -> Self294     pub fn new(bound_vars: &'tcx ty::List<ty::BoundVariableKind>) -> Self {
295         ValidateBoundVars {
296             bound_vars,
297             binder_index: ty::INNERMOST,
298             visited: SsoHashSet::default(),
299         }
300     }
301 }
302 
303 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ValidateBoundVars<'tcx> {
304     type BreakTy = ();
305 
visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>( &mut self, t: &Binder<'tcx, T>, ) -> ControlFlow<Self::BreakTy>306     fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
307         &mut self,
308         t: &Binder<'tcx, T>,
309     ) -> ControlFlow<Self::BreakTy> {
310         self.binder_index.shift_in(1);
311         let result = t.super_visit_with(self);
312         self.binder_index.shift_out(1);
313         result
314     }
315 
visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy>316     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
317         if t.outer_exclusive_binder() < self.binder_index
318             || !self.visited.insert((self.binder_index, t))
319         {
320             return ControlFlow::Break(());
321         }
322         match *t.kind() {
323             ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
324                 if self.bound_vars.len() <= bound_ty.var.as_usize() {
325                     bug!("Not enough bound vars: {:?} not found in {:?}", t, self.bound_vars);
326                 }
327                 let list_var = self.bound_vars[bound_ty.var.as_usize()];
328                 match list_var {
329                     ty::BoundVariableKind::Ty(kind) => {
330                         if kind != bound_ty.kind {
331                             bug!(
332                                 "Mismatched type kinds: {:?} doesn't var in list {:?}",
333                                 bound_ty.kind,
334                                 list_var
335                             );
336                         }
337                     }
338                     _ => {
339                         bug!("Mismatched bound variable kinds! Expected type, found {:?}", list_var)
340                     }
341                 }
342             }
343 
344             _ => (),
345         };
346 
347         t.super_visit_with(self)
348     }
349 
visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy>350     fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
351         match *r {
352             ty::ReLateBound(index, br) if index == self.binder_index => {
353                 if self.bound_vars.len() <= br.var.as_usize() {
354                     bug!("Not enough bound vars: {:?} not found in {:?}", br, self.bound_vars);
355                 }
356                 let list_var = self.bound_vars[br.var.as_usize()];
357                 match list_var {
358                     ty::BoundVariableKind::Region(kind) => {
359                         if kind != br.kind {
360                             bug!(
361                                 "Mismatched region kinds: {:?} doesn't match var ({:?}) in list ({:?})",
362                                 br.kind,
363                                 list_var,
364                                 self.bound_vars
365                             );
366                         }
367                     }
368                     _ => bug!(
369                         "Mismatched bound variable kinds! Expected region, found {:?}",
370                         list_var
371                     ),
372                 }
373             }
374 
375             _ => (),
376         };
377 
378         ControlFlow::Continue(())
379     }
380 }
381 
382 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
383 struct FoundEscapingVars;
384 
385 /// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a
386 /// bound region or a bound type.
387 ///
388 /// So, for example, consider a type like the following, which has two binders:
389 ///
390 ///    for<'a> fn(x: for<'b> fn(&'a isize, &'b isize))
391 ///    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ outer scope
392 ///                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~  inner scope
393 ///
394 /// This type has *bound regions* (`'a`, `'b`), but it does not have escaping regions, because the
395 /// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner
396 /// fn type*, that type has an escaping region: `'a`.
397 ///
398 /// Note that what I'm calling an "escaping var" is often just called a "free var". However,
399 /// we already use the term "free var". It refers to the regions or types that we use to represent
400 /// bound regions or type params on a fn definition while we are type checking its body.
401 ///
402 /// To clarify, conceptually there is no particular difference between
403 /// an "escaping" var and a "free" var. However, there is a big
404 /// difference in practice. Basically, when "entering" a binding
405 /// level, one is generally required to do some sort of processing to
406 /// a bound var, such as replacing it with a fresh/placeholder
407 /// var, or making an entry in the environment to represent the
408 /// scope to which it is attached, etc. An escaping var represents
409 /// a bound var for which this processing has not yet been done.
410 struct HasEscapingVarsVisitor {
411     /// Anything bound by `outer_index` or "above" is escaping.
412     outer_index: ty::DebruijnIndex,
413 }
414 
415 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasEscapingVarsVisitor {
416     type BreakTy = FoundEscapingVars;
417 
visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>( &mut self, t: &Binder<'tcx, T>, ) -> ControlFlow<Self::BreakTy>418     fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
419         &mut self,
420         t: &Binder<'tcx, T>,
421     ) -> ControlFlow<Self::BreakTy> {
422         self.outer_index.shift_in(1);
423         let result = t.super_visit_with(self);
424         self.outer_index.shift_out(1);
425         result
426     }
427 
428     #[inline]
visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy>429     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
430         // If the outer-exclusive-binder is *strictly greater* than
431         // `outer_index`, that means that `t` contains some content
432         // bound at `outer_index` or above (because
433         // `outer_exclusive_binder` is always 1 higher than the
434         // content in `t`). Therefore, `t` has some escaping vars.
435         if t.outer_exclusive_binder() > self.outer_index {
436             ControlFlow::Break(FoundEscapingVars)
437         } else {
438             ControlFlow::Continue(())
439         }
440     }
441 
442     #[inline]
visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy>443     fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
444         // If the region is bound by `outer_index` or anything outside
445         // of outer index, then it escapes the binders we have
446         // visited.
447         if r.bound_at_or_above_binder(self.outer_index) {
448             ControlFlow::Break(FoundEscapingVars)
449         } else {
450             ControlFlow::Continue(())
451         }
452     }
453 
visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy>454     fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
455         // we don't have a `visit_infer_const` callback, so we have to
456         // hook in here to catch this case (annoying...), but
457         // otherwise we do want to remember to visit the rest of the
458         // const, as it has types/regions embedded in a lot of other
459         // places.
460         match ct.kind() {
461             ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => {
462                 ControlFlow::Break(FoundEscapingVars)
463             }
464             _ => ct.super_visit_with(self),
465         }
466     }
467 
468     #[inline]
visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy>469     fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
470         if predicate.outer_exclusive_binder() > self.outer_index {
471             ControlFlow::Break(FoundEscapingVars)
472         } else {
473             ControlFlow::Continue(())
474         }
475     }
476 }
477 
478 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
479 struct FoundFlags;
480 
481 // FIXME: Optimize for checking for infer flags
482 struct HasTypeFlagsVisitor {
483     flags: ty::TypeFlags,
484 }
485 
486 impl std::fmt::Debug for HasTypeFlagsVisitor {
fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result487     fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
488         self.flags.fmt(fmt)
489     }
490 }
491 
492 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasTypeFlagsVisitor {
493     type BreakTy = FoundFlags;
494 
495     #[inline]
visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy>496     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
497         let flags = t.flags();
498         if flags.intersects(self.flags) {
499             ControlFlow::Break(FoundFlags)
500         } else {
501             ControlFlow::Continue(())
502         }
503     }
504 
505     #[inline]
visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy>506     fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
507         let flags = r.type_flags();
508         if flags.intersects(self.flags) {
509             ControlFlow::Break(FoundFlags)
510         } else {
511             ControlFlow::Continue(())
512         }
513     }
514 
515     #[inline]
visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy>516     fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
517         let flags = FlagComputation::for_const(c);
518         trace!(r.flags=?flags);
519         if flags.intersects(self.flags) {
520             ControlFlow::Break(FoundFlags)
521         } else {
522             ControlFlow::Continue(())
523         }
524     }
525 
526     #[inline]
visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy>527     fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
528         if predicate.flags().intersects(self.flags) {
529             ControlFlow::Break(FoundFlags)
530         } else {
531             ControlFlow::Continue(())
532         }
533     }
534 }
535 
536 /// Collects all the late-bound regions at the innermost binding level
537 /// into a hash set.
538 struct LateBoundRegionsCollector {
539     current_index: ty::DebruijnIndex,
540     regions: FxHashSet<ty::BoundRegionKind>,
541 
542     /// `true` if we only want regions that are known to be
543     /// "constrained" when you equate this type with another type. In
544     /// particular, if you have e.g., `&'a u32` and `&'b u32`, equating
545     /// them constraints `'a == 'b`. But if you have `<&'a u32 as
546     /// Trait>::Foo` and `<&'b u32 as Trait>::Foo`, normalizing those
547     /// types may mean that `'a` and `'b` don't appear in the results,
548     /// so they are not considered *constrained*.
549     just_constrained: bool,
550 }
551 
552 impl LateBoundRegionsCollector {
new(just_constrained: bool) -> Self553     fn new(just_constrained: bool) -> Self {
554         LateBoundRegionsCollector {
555             current_index: ty::INNERMOST,
556             regions: Default::default(),
557             just_constrained,
558         }
559     }
560 }
561 
562 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for LateBoundRegionsCollector {
visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>( &mut self, t: &Binder<'tcx, T>, ) -> ControlFlow<Self::BreakTy>563     fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
564         &mut self,
565         t: &Binder<'tcx, T>,
566     ) -> ControlFlow<Self::BreakTy> {
567         self.current_index.shift_in(1);
568         let result = t.super_visit_with(self);
569         self.current_index.shift_out(1);
570         result
571     }
572 
visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy>573     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
574         // if we are only looking for "constrained" region, we have to
575         // ignore the inputs to a projection, as they may not appear
576         // in the normalized form
577         if self.just_constrained {
578             if let ty::Alias(..) = t.kind() {
579                 return ControlFlow::Continue(());
580             }
581         }
582 
583         t.super_visit_with(self)
584     }
585 
visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy>586     fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
587         // if we are only looking for "constrained" region, we have to
588         // ignore the inputs of an unevaluated const, as they may not appear
589         // in the normalized form
590         if self.just_constrained {
591             if let ty::ConstKind::Unevaluated(..) = c.kind() {
592                 return ControlFlow::Continue(());
593             }
594         }
595 
596         c.super_visit_with(self)
597     }
598 
visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy>599     fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
600         if let ty::ReLateBound(debruijn, br) = *r {
601             if debruijn == self.current_index {
602                 self.regions.insert(br.kind);
603             }
604         }
605         ControlFlow::Continue(())
606     }
607 }
608 
609 /// Finds the max universe present
610 pub struct MaxUniverse {
611     max_universe: ty::UniverseIndex,
612 }
613 
614 impl MaxUniverse {
new() -> Self615     pub fn new() -> Self {
616         MaxUniverse { max_universe: ty::UniverseIndex::ROOT }
617     }
618 
max_universe(self) -> ty::UniverseIndex619     pub fn max_universe(self) -> ty::UniverseIndex {
620         self.max_universe
621     }
622 }
623 
624 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MaxUniverse {
visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy>625     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
626         if let ty::Placeholder(placeholder) = t.kind() {
627             self.max_universe = ty::UniverseIndex::from_u32(
628                 self.max_universe.as_u32().max(placeholder.universe.as_u32()),
629             );
630         }
631 
632         t.super_visit_with(self)
633     }
634 
visit_const(&mut self, c: ty::consts::Const<'tcx>) -> ControlFlow<Self::BreakTy>635     fn visit_const(&mut self, c: ty::consts::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
636         if let ty::ConstKind::Placeholder(placeholder) = c.kind() {
637             self.max_universe = ty::UniverseIndex::from_u32(
638                 self.max_universe.as_u32().max(placeholder.universe.as_u32()),
639             );
640         }
641 
642         c.super_visit_with(self)
643     }
644 
visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy>645     fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
646         if let ty::RePlaceholder(placeholder) = *r {
647             self.max_universe = ty::UniverseIndex::from_u32(
648                 self.max_universe.as_u32().max(placeholder.universe.as_u32()),
649             );
650         }
651 
652         ControlFlow::Continue(())
653     }
654 }
655