Skip to main content

rustc_type_ir/
visit.rs

1//! A visiting traversal mechanism for complex data structures that contain type
2//! information.
3//!
4//! This is a read-only traversal of the data structure.
5//!
6//! This traversal has limited flexibility. Only a small number of "types of
7//! interest" within the complex data structures can receive custom
8//! visitation. These are the ones containing the most important type-related
9//! information, such as `Ty`, `Predicate`, `Region`, and `Const`.
10//!
11//! There are three traits involved in each traversal.
12//! - `TypeVisitable`. This is implemented once for many types, including:
13//!   - Types of interest, for which the methods delegate to the visitor.
14//!   - All other types, including generic containers like `Vec` and `Option`.
15//!     It defines a "skeleton" of how they should be visited.
16//! - `TypeSuperVisitable`. This is implemented only for recursive types of
17//!   interest, and defines the visiting "skeleton" for these types. (This
18//!   excludes `Region` because it is non-recursive, i.e. it never contains
19//!   other types of interest.)
20//! - `TypeVisitor`. This is implemented for each visitor. This defines how
21//!   types of interest are visited.
22//!
23//! This means each visit is a mixture of (a) generic visiting operations, and (b)
24//! custom visit operations that are specific to the visitor.
25//! - The `TypeVisitable` impls handle most of the traversal, and call into
26//!   `TypeVisitor` when they encounter a type of interest.
27//! - A `TypeVisitor` may call into another `TypeVisitable` impl, because some of
28//!   the types of interest are recursive and can contain other types of interest.
29//! - A `TypeVisitor` may also call into a `TypeSuperVisitable` impl, because each
30//!   visitor might provide custom handling only for some types of interest, or
31//!   only for some variants of each type of interest, and then use default
32//!   traversal for the remaining cases.
33//!
34//! For example, if you have `struct S(Ty, U)` where `S: TypeVisitable` and `U:
35//! TypeVisitable`, and an instance `s = S(ty, u)`, it would be visited like so:
36//! ```text
37//! s.visit_with(visitor) calls
38//! - ty.visit_with(visitor) calls
39//!   - visitor.visit_ty(ty) may call
40//!     - ty.super_visit_with(visitor)
41//! - u.visit_with(visitor)
42//! ```
43
44use std::fmt;
45use std::ops::ControlFlow;
46use std::sync::Arc;
47
48pub use rustc_ast_ir::visit::VisitorResult;
49pub use rustc_ast_ir::{try_visit, walk_visitable_list};
50use rustc_index::{Idx, IndexVec};
51use smallvec::SmallVec;
52use thin_vec::ThinVec;
53
54use crate::inherent::*;
55use crate::{self as ty, Const, Interner, PredicateProxy, Region, TypeFlags};
56
57/// This trait is implemented for every type that can be visited,
58/// providing the skeleton of the traversal.
59///
60/// To implement this conveniently, use the derive macro located in
61/// `rustc_macros`.
62#[cfg_attr(feature = "nightly", rustc_diagnostic_item = "TypeVisitable")]
63pub trait TypeVisitable<I: Interner>: fmt::Debug {
64    /// The entry point for visiting. To visit a value `t` with a visitor `v`
65    /// call: `t.visit_with(v)`.
66    ///
67    /// For most types, this just traverses the value, calling `visit_with` on
68    /// each field/element.
69    ///
70    /// For types of interest (such as `Ty`), the implementation of this method
71    /// calls a visitor method specifically for that type (such as
72    /// `V::visit_ty`). This is where control transfers from `TypeVisitable` to
73    /// `TypeVisitor`.
74    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result;
75}
76
77// This trait is implemented for types of interest.
78pub trait TypeSuperVisitable<I: Interner>: TypeVisitable<I> {
79    /// Provides a default visit for a recursive type of interest. This should
80    /// only be called within `TypeVisitor` methods, when a non-custom
81    /// traversal is desired for the value of the type of interest passed to
82    /// that method. For example, in `MyVisitor::visit_ty(ty)`, it is valid to
83    /// call `ty.super_visit_with(self)`, but any other visiting should be done
84    /// with `xyz.visit_with(self)`.
85    fn super_visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result;
86}
87
88/// This trait is implemented for every visiting traversal. There is a visit
89/// method defined for every type of interest. Each such method has a default
90/// that recurses into the type's fields in a non-custom fashion.
91pub trait TypeVisitor<I: Interner>: Sized {
92    #[cfg(feature = "nightly")]
93    type Result: VisitorResult = ();
94
95    #[cfg(not(feature = "nightly"))]
96    type Result: VisitorResult;
97
98    fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
99        t.super_visit_with(self)
100    }
101
102    fn visit_ty(&mut self, t: I::Ty) -> Self::Result {
103        t.super_visit_with(self)
104    }
105
106    // `Region` is non-recursive so the default region visitor has no
107    // `super_visit_with` method to call.
108    fn visit_region(&mut self, r: Region<I>) -> Self::Result {
109        if let ty::ReError(guar) = r.kind() {
110            self.visit_error(guar)
111        } else {
112            Self::Result::output()
113        }
114    }
115
116    fn visit_const(&mut self, c: Const<I>) -> Self::Result {
117        c.super_visit_with(self)
118    }
119
120    fn visit_predicate<P: PredicateProxy<I>>(&mut self, p: P) -> Self::Result {
121        p.super_visit_with(self)
122    }
123
124    fn visit_clauses(&mut self, c: I::Clauses) -> Self::Result {
125        c.super_visit_with(self)
126    }
127
128    fn visit_error(&mut self, _guar: I::ErrorGuaranteed) -> Self::Result {
129        Self::Result::output()
130    }
131}
132
133///////////////////////////////////////////////////////////////////////////
134// Traversal implementations.
135
136impl<I: Interner, T: TypeVisitable<I>, U: TypeVisitable<I>> TypeVisitable<I> for (T, U) {
137    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
138        match ::rustc_ast_ir::visit::VisitorResult::branch(self.0.visit_with(visitor))
    {
    core::ops::ControlFlow::Continue(()) =>
        (),
        #[allow(unreachable_code)]
        core::ops::ControlFlow::Break(r) => {
        return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
    }
};try_visit!(self.0.visit_with(visitor));
139        self.1.visit_with(visitor)
140    }
141}
142
143impl<I: Interner, A: TypeVisitable<I>, B: TypeVisitable<I>, C: TypeVisitable<I>> TypeVisitable<I>
144    for (A, B, C)
145{
146    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
147        match ::rustc_ast_ir::visit::VisitorResult::branch(self.0.visit_with(visitor))
    {
    core::ops::ControlFlow::Continue(()) =>
        (),
        #[allow(unreachable_code)]
        core::ops::ControlFlow::Break(r) => {
        return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
    }
};try_visit!(self.0.visit_with(visitor));
148        match ::rustc_ast_ir::visit::VisitorResult::branch(self.1.visit_with(visitor))
    {
    core::ops::ControlFlow::Continue(()) =>
        (),
        #[allow(unreachable_code)]
        core::ops::ControlFlow::Break(r) => {
        return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
    }
};try_visit!(self.1.visit_with(visitor));
149        self.2.visit_with(visitor)
150    }
151}
152
153impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Option<T> {
154    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
155        match self {
156            Some(v) => v.visit_with(visitor),
157            None => V::Result::output(),
158        }
159    }
160}
161
162impl<I: Interner, T: TypeVisitable<I>, E: TypeVisitable<I>> TypeVisitable<I> for Result<T, E> {
163    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
164        match self {
165            Ok(v) => v.visit_with(visitor),
166            Err(e) => e.visit_with(visitor),
167        }
168    }
169}
170
171impl<I: Interner, T: TypeVisitable<I> + ?Sized> TypeVisitable<I> for &T {
172    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
173        (**self).visit_with(visitor)
174    }
175}
176
177impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Arc<T> {
178    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
179        (**self).visit_with(visitor)
180    }
181}
182
183impl<I: Interner, T: TypeVisitable<I> + ?Sized> TypeVisitable<I> for Box<T> {
184    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
185        (**self).visit_with(visitor)
186    }
187}
188
189impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Vec<T> {
190    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
191        for elem in self.iter() {
    match ::rustc_ast_ir::visit::VisitorResult::branch(::rustc_type_ir::TypeVisitable::visit_with(elem,
                visitor)) {
        core::ops::ControlFlow::Continue(()) =>
            (),
            #[allow(unreachable_code)]
            core::ops::ControlFlow::Break(r) => {
            return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
        }
    };
};walk_visitable_list!(visitor, self.iter());
192        V::Result::output()
193    }
194}
195
196impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for ThinVec<T> {
197    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
198        for elem in self.iter() {
    match ::rustc_ast_ir::visit::VisitorResult::branch(::rustc_type_ir::TypeVisitable::visit_with(elem,
                visitor)) {
        core::ops::ControlFlow::Continue(()) =>
            (),
            #[allow(unreachable_code)]
            core::ops::ControlFlow::Break(r) => {
            return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
        }
    };
};walk_visitable_list!(visitor, self.iter());
199        V::Result::output()
200    }
201}
202
203impl<I: Interner, T: TypeVisitable<I>, const N: usize> TypeVisitable<I> for SmallVec<[T; N]> {
204    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
205        for elem in self.iter() {
    match ::rustc_ast_ir::visit::VisitorResult::branch(::rustc_type_ir::TypeVisitable::visit_with(elem,
                visitor)) {
        core::ops::ControlFlow::Continue(()) =>
            (),
            #[allow(unreachable_code)]
            core::ops::ControlFlow::Break(r) => {
            return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
        }
    };
};walk_visitable_list!(visitor, self.iter());
206        V::Result::output()
207    }
208}
209
210// `TypeFoldable` isn't impl'd for `&[T]`. It doesn't make sense in the general
211// case, because we can't return a new slice. But note that there are a couple
212// of trivial impls of `TypeFoldable` for specific slice types elsewhere.
213impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for [T] {
214    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
215        for elem in self.iter() {
    match ::rustc_ast_ir::visit::VisitorResult::branch(::rustc_type_ir::TypeVisitable::visit_with(elem,
                visitor)) {
        core::ops::ControlFlow::Continue(()) =>
            (),
            #[allow(unreachable_code)]
            core::ops::ControlFlow::Break(r) => {
            return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
        }
    };
};walk_visitable_list!(visitor, self.iter());
216        V::Result::output()
217    }
218}
219
220impl<const N: usize, I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for [T; N] {
221    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
222        for elem in self.iter() {
    match ::rustc_ast_ir::visit::VisitorResult::branch(::rustc_type_ir::TypeVisitable::visit_with(elem,
                visitor)) {
        core::ops::ControlFlow::Continue(()) =>
            (),
            #[allow(unreachable_code)]
            core::ops::ControlFlow::Break(r) => {
            return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
        }
    };
};walk_visitable_list!(visitor, self.iter());
223        V::Result::output()
224    }
225}
226
227impl<I: Interner, T: TypeVisitable<I>, Ix: Idx> TypeVisitable<I> for IndexVec<Ix, T> {
228    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
229        for elem in self.iter() {
    match ::rustc_ast_ir::visit::VisitorResult::branch(::rustc_type_ir::TypeVisitable::visit_with(elem,
                visitor)) {
        core::ops::ControlFlow::Continue(()) =>
            (),
            #[allow(unreachable_code)]
            core::ops::ControlFlow::Break(r) => {
            return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
        }
    };
};walk_visitable_list!(visitor, self.iter());
230        V::Result::output()
231    }
232}
233
234impl<I: Interner, T: TypeVisitable<I>, S> TypeVisitable<I> for indexmap::IndexSet<T, S> {
235    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
236        for elem in self.iter() {
    match ::rustc_ast_ir::visit::VisitorResult::branch(::rustc_type_ir::TypeVisitable::visit_with(elem,
                visitor)) {
        core::ops::ControlFlow::Continue(()) =>
            (),
            #[allow(unreachable_code)]
            core::ops::ControlFlow::Break(r) => {
            return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
        }
    };
};walk_visitable_list!(visitor, self.iter());
237        V::Result::output()
238    }
239}
240
241pub trait Flags {
242    fn flags(&self) -> TypeFlags;
243    fn outer_exclusive_binder(&self) -> ty::DebruijnIndex;
244}
245
246pub trait TypeVisitableExt<I: Interner>: TypeVisitable<I> {
247    fn has_type_flags(&self, flags: TypeFlags) -> bool;
248
249    /// Returns `true` if `self` has any late-bound regions that are either
250    /// bound by `binder` or bound by some binder outside of `binder`.
251    /// If `binder` is `ty::INNERMOST`, this indicates whether
252    /// there are any late-bound regions that appear free.
253    fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool;
254
255    /// Returns `true` if this type has any regions that escape `binder` (and
256    /// hence are not bound by it).
257    fn has_vars_bound_above(&self, binder: ty::DebruijnIndex) -> bool {
258        self.has_vars_bound_at_or_above(binder.shifted_in(1))
259    }
260
261    /// Returns `true` if this type has regions that are not a part of the
262    /// type. For example, given a `for<'a> fn(&'a i32)` this function returns
263    /// `false`, while given a `fn(&'a i32)` it returns `true`. The latter can
264    /// occur when traversing through the former.
265    ///
266    /// See [`HasEscapingVarsVisitor`] for more information.
267    fn has_escaping_bound_vars(&self) -> bool {
268        self.has_vars_bound_at_or_above(ty::INNERMOST)
269    }
270
271    fn has_aliases(&self) -> bool {
272        self.has_type_flags(TypeFlags::HAS_ALIAS)
273    }
274
275    fn has_opaque_types(&self) -> bool {
276        self.has_type_flags(TypeFlags::HAS_TY_OPAQUE)
277    }
278
279    fn has_coroutines(&self) -> bool {
280        self.has_type_flags(TypeFlags::HAS_TY_CORO)
281    }
282
283    fn references_error(&self) -> bool {
284        self.has_type_flags(TypeFlags::HAS_ERROR)
285    }
286
287    fn error_reported(&self) -> Result<(), I::ErrorGuaranteed>;
288
289    fn non_region_error_reported(&self) -> Result<(), I::ErrorGuaranteed>;
290
291    fn has_non_region_param(&self) -> bool {
292        self.has_type_flags(TypeFlags::HAS_PARAM - TypeFlags::HAS_RE_PARAM)
293    }
294
295    fn has_regions(&self) -> bool {
296        self.has_type_flags(TypeFlags::HAS_REGIONS)
297    }
298
299    fn has_infer_regions(&self) -> bool {
300        self.has_type_flags(TypeFlags::HAS_RE_INFER)
301    }
302
303    fn has_infer_types(&self) -> bool {
304        self.has_type_flags(TypeFlags::HAS_TY_INFER)
305    }
306
307    fn has_non_region_infer(&self) -> bool {
308        self.has_type_flags(TypeFlags::HAS_INFER - TypeFlags::HAS_RE_INFER)
309    }
310
311    fn has_infer(&self) -> bool {
312        self.has_type_flags(TypeFlags::HAS_INFER)
313    }
314
315    fn has_placeholders(&self) -> bool {
316        self.has_type_flags(TypeFlags::HAS_PLACEHOLDER)
317    }
318
319    fn has_non_region_placeholders(&self) -> bool {
320        self.has_type_flags(TypeFlags::HAS_PLACEHOLDER - TypeFlags::HAS_RE_PLACEHOLDER)
321    }
322
323    fn has_param(&self) -> bool {
324        self.has_type_flags(TypeFlags::HAS_PARAM)
325    }
326
327    /// "Free" regions in this context means that it has any region
328    /// that is not (a) erased or (b) late-bound.
329    fn has_free_regions(&self) -> bool {
330        self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
331    }
332
333    fn has_erased_regions(&self) -> bool {
334        self.has_type_flags(TypeFlags::HAS_RE_ERASED)
335    }
336
337    /// True if there are any un-erased free regions.
338    fn has_erasable_regions(&self) -> bool {
339        self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
340    }
341
342    /// Indicates whether this value references only 'global'
343    /// generic parameters that are the same regardless of what fn we are
344    /// in. This is used for caching.
345    fn is_global(&self) -> bool {
346        !self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES)
347    }
348
349    /// True if there are any late-bound regions
350    fn has_bound_regions(&self) -> bool {
351        self.has_type_flags(TypeFlags::HAS_RE_BOUND)
352    }
353    /// True if there are any late-bound non-region variables
354    fn has_non_region_bound_vars(&self) -> bool {
355        self.has_type_flags(TypeFlags::HAS_BOUND_VARS - TypeFlags::HAS_RE_BOUND)
356    }
357    /// True if there are any bound variables
358    fn has_bound_vars(&self) -> bool {
359        self.has_type_flags(TypeFlags::HAS_BOUND_VARS)
360    }
361
362    /// Indicates whether this value still has parameters/placeholders/inference variables
363    /// which could be replaced later, in a way that would change the results of `impl`
364    /// specialization.
365    fn still_further_specializable(&self) -> bool {
366        self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE)
367    }
368
369    /// True if a type or const error is reachable
370    fn has_non_region_error(&self) -> bool {
371        self.has_type_flags(TypeFlags::HAS_NON_REGION_ERROR)
372    }
373
374    /// True if an alias has `IsRigid::Yes`. Used for skipping normalization.
375    fn has_rigid_aliases(&self) -> bool {
376        self.has_type_flags(TypeFlags::HAS_RIGID_ALIAS)
377    }
378
379    /// True if an alias has `IsRigid::No`.
380    fn has_non_rigid_aliases(&self) -> bool {
381        self.has_type_flags(TypeFlags::HAS_NON_RIGID_ALIAS)
382    }
383}
384
385impl<I: Interner, T: TypeVisitable<I>> TypeVisitableExt<I> for T {
386    fn has_type_flags(&self, flags: TypeFlags) -> bool {
387        self.visit_with(&mut HasTypeFlagsVisitor { flags }) == ControlFlow::Break(FoundFlags)
388    }
389
390    fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
391        self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder })
392            == ControlFlow::Break(FoundEscapingVars)
393    }
394
395    fn error_reported(&self) -> Result<(), I::ErrorGuaranteed> {
396        if self.references_error() {
397            if let ControlFlow::Break(guar) = self.visit_with(&mut HasErrorVisitor) {
398                Err(guar)
399            } else {
400                {
    ::core::panicking::panic_fmt(format_args!("type flags said there was an error, but now there is not"));
}panic!("type flags said there was an error, but now there is not")
401            }
402        } else {
403            Ok(())
404        }
405    }
406
407    fn non_region_error_reported(&self) -> Result<(), I::ErrorGuaranteed> {
408        if self.has_non_region_error() {
409            if let ControlFlow::Break(guar) = self.visit_with(&mut HasErrorVisitor) {
410                Err(guar)
411            } else {
412                {
    ::core::panicking::panic_fmt(format_args!("type flags said there was an non region error, but now there is not"));
}panic!("type flags said there was an non region error, but now there is not")
413            }
414        } else {
415            Ok(())
416        }
417    }
418}
419
420#[derive(#[automatically_derived]
impl ::core::fmt::Debug for FoundFlags {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "FoundFlags")
    }
}Debug, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for FoundFlags { }
#[automatically_derived]
impl ::core::cmp::PartialEq for FoundFlags {
    #[inline]
    fn eq(&self, other: &Self) -> bool { true }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for FoundFlags { }Eq, #[automatically_derived]
impl ::core::marker::Copy for FoundFlags { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for FoundFlags { }
#[automatically_derived]
impl ::core::clone::Clone for FoundFlags {
    #[inline]
    fn clone(&self) -> Self { *self }
}Clone)]
421struct FoundFlags;
422
423// FIXME: Optimize for checking for infer flags
424struct HasTypeFlagsVisitor {
425    flags: ty::TypeFlags,
426}
427
428impl std::fmt::Debug for HasTypeFlagsVisitor {
429    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
430        self.flags.fmt(fmt)
431    }
432}
433
434// Note: this visitor traverses values down to the level of
435// `Ty`/`Const`/`Predicate`, but not within those types. This is because the
436// type flags at the outer layer are enough. So it's faster than it first
437// looks, particular for `Ty`/`Predicate` where it's just a field access.
438//
439// N.B. The only case where this isn't totally true is binders, which also
440// add `HAS_BINDER_VARS` flag depending on the *bound variables* that
441// are present, regardless of whether those bound variables are used. This
442// is important for anonymization of binders in `TyCtxt::erase_and_anonymize_regions`. We
443// specifically detect this case in `visit_binder`.
444impl<I: Interner> TypeVisitor<I> for HasTypeFlagsVisitor {
445    type Result = ControlFlow<FoundFlags>;
446
447    fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
448        // If we're looking for the HAS_BINDER_VARS flag, check if the
449        // binder has vars. This won't be present in the binder's bound
450        // value, so we need to check here too.
451        if self.flags.intersects(TypeFlags::HAS_BINDER_VARS) && !t.bound_vars().is_empty() {
452            return ControlFlow::Break(FoundFlags);
453        }
454
455        t.super_visit_with(self)
456    }
457
458    #[inline]
459    fn visit_ty(&mut self, t: I::Ty) -> Self::Result {
460        // Note: no `super_visit_with` call.
461        if t.flags().intersects(self.flags) {
462            ControlFlow::Break(FoundFlags)
463        } else {
464            ControlFlow::Continue(())
465        }
466    }
467
468    #[inline]
469    fn visit_region(&mut self, r: Region<I>) -> Self::Result {
470        // Note: no `super_visit_with` call, as usual for `Region`.
471        if r.flags().intersects(self.flags) {
472            ControlFlow::Break(FoundFlags)
473        } else {
474            ControlFlow::Continue(())
475        }
476    }
477
478    #[inline]
479    fn visit_const(&mut self, c: Const<I>) -> Self::Result {
480        // Note: no `super_visit_with` call.
481        if c.flags().intersects(self.flags) {
482            ControlFlow::Break(FoundFlags)
483        } else {
484            ControlFlow::Continue(())
485        }
486    }
487
488    #[inline]
489    fn visit_predicate<P: PredicateProxy<I>>(&mut self, predicate: P) -> Self::Result {
490        // Note: no `super_visit_with` call.
491        if predicate.flags().intersects(self.flags) {
492            ControlFlow::Break(FoundFlags)
493        } else {
494            ControlFlow::Continue(())
495        }
496    }
497
498    #[inline]
499    fn visit_clauses(&mut self, clauses: I::Clauses) -> Self::Result {
500        // Note: no `super_visit_with` call.
501        if clauses.flags().intersects(self.flags) {
502            ControlFlow::Break(FoundFlags)
503        } else {
504            ControlFlow::Continue(())
505        }
506    }
507
508    #[inline]
509    fn visit_error(&mut self, _guar: <I as Interner>::ErrorGuaranteed) -> Self::Result {
510        if self.flags.intersects(TypeFlags::HAS_ERROR) {
511            ControlFlow::Break(FoundFlags)
512        } else {
513            ControlFlow::Continue(())
514        }
515    }
516}
517
518#[derive(#[automatically_derived]
impl ::core::fmt::Debug for FoundEscapingVars {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "FoundEscapingVars")
    }
}Debug, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for FoundEscapingVars { }
#[automatically_derived]
impl ::core::cmp::PartialEq for FoundEscapingVars {
    #[inline]
    fn eq(&self, other: &Self) -> bool { true }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for FoundEscapingVars { }Eq, #[automatically_derived]
impl ::core::marker::Copy for FoundEscapingVars { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for FoundEscapingVars { }
#[automatically_derived]
impl ::core::clone::Clone for FoundEscapingVars {
    #[inline]
    fn clone(&self) -> Self { *self }
}Clone)]
519struct FoundEscapingVars;
520
521/// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a
522/// bound region or a bound type.
523///
524/// So, for example, consider a type like the following, which has two binders:
525///
526///    for<'a> fn(x: for<'b> fn(&'a isize, &'b isize))
527///    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ outer scope
528///                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~  inner scope
529///
530/// This type has *bound regions* (`'a`, `'b`), but it does not have escaping regions, because the
531/// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner
532/// fn type*, that type has an escaping region: `'a`.
533///
534/// Note that what I'm calling an "escaping var" is often just called a "free var". However,
535/// we already use the term "free var". It refers to the regions or types that we use to represent
536/// bound regions or type params on a fn definition while we are type checking its body.
537///
538/// To clarify, conceptually there is no particular difference between
539/// an "escaping" var and a "free" var. However, there is a big
540/// difference in practice. Basically, when "entering" a binding
541/// level, one is generally required to do some sort of processing to
542/// a bound var, such as replacing it with a fresh/placeholder
543/// var, or making an entry in the environment to represent the
544/// scope to which it is attached, etc. An escaping var represents
545/// a bound var for which this processing has not yet been done.
546struct HasEscapingVarsVisitor {
547    /// Anything bound by `outer_index` or "above" is escaping.
548    outer_index: ty::DebruijnIndex,
549}
550
551impl<I: Interner> TypeVisitor<I> for HasEscapingVarsVisitor {
552    type Result = ControlFlow<FoundEscapingVars>;
553
554    fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
555        self.outer_index.shift_in(1);
556        let result = t.super_visit_with(self);
557        self.outer_index.shift_out(1);
558        result
559    }
560
561    #[inline]
562    fn visit_ty(&mut self, t: I::Ty) -> Self::Result {
563        // If the outer-exclusive-binder is *strictly greater* than
564        // `outer_index`, that means that `t` contains some content
565        // bound at `outer_index` or above (because
566        // `outer_exclusive_binder` is always 1 higher than the
567        // content in `t`). Therefore, `t` has some escaping vars.
568        if t.outer_exclusive_binder() > self.outer_index {
569            ControlFlow::Break(FoundEscapingVars)
570        } else {
571            ControlFlow::Continue(())
572        }
573    }
574
575    #[inline]
576    fn visit_region(&mut self, r: Region<I>) -> Self::Result {
577        // If the region is bound by `outer_index` or anything outside
578        // of outer index, then it escapes the binders we have
579        // visited.
580        if r.outer_exclusive_binder() > self.outer_index {
581            ControlFlow::Break(FoundEscapingVars)
582        } else {
583            ControlFlow::Continue(())
584        }
585    }
586
587    fn visit_const(&mut self, ct: Const<I>) -> Self::Result {
588        // If the outer-exclusive-binder is *strictly greater* than
589        // `outer_index`, that means that `ct` contains some content
590        // bound at `outer_index` or above (because
591        // `outer_exclusive_binder` is always 1 higher than the
592        // content in `ct`). Therefore, `ct` has some escaping vars.
593        if ct.outer_exclusive_binder() > self.outer_index {
594            ControlFlow::Break(FoundEscapingVars)
595        } else {
596            ControlFlow::Continue(())
597        }
598    }
599
600    #[inline]
601    fn visit_predicate<P: PredicateProxy<I>>(&mut self, predicate: P) -> Self::Result {
602        if predicate.outer_exclusive_binder() > self.outer_index {
603            ControlFlow::Break(FoundEscapingVars)
604        } else {
605            ControlFlow::Continue(())
606        }
607    }
608
609    #[inline]
610    fn visit_clauses(&mut self, clauses: I::Clauses) -> Self::Result {
611        if clauses.outer_exclusive_binder() > self.outer_index {
612            ControlFlow::Break(FoundEscapingVars)
613        } else {
614            ControlFlow::Continue(())
615        }
616    }
617}
618
619struct HasErrorVisitor;
620
621impl<I: Interner> TypeVisitor<I> for HasErrorVisitor {
622    type Result = ControlFlow<I::ErrorGuaranteed>;
623
624    fn visit_error(&mut self, guar: <I as Interner>::ErrorGuaranteed) -> Self::Result {
625        ControlFlow::Break(guar)
626    }
627}