about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlan Egerton <eggyal@gmail.com>2023-02-09 12:56:33 +0000
committerAlan Egerton <eggyal@gmail.com>2023-02-13 10:24:45 +0000
commit62846d7c99ca4e17be8c6867fc4b50d10c8a6ec1 (patch)
tree864a1ed313967064ef4fc0afda1d3fc715db2b9d
parent20081880ad2a98bbc8c8293f96c5b284d1584d86 (diff)
downloadrust-62846d7c99ca4e17be8c6867fc4b50d10c8a6ec1.tar.gz
rust-62846d7c99ca4e17be8c6867fc4b50d10c8a6ec1.zip
Move folding & visiting traits to ir submodules
-rw-r--r--compiler/rustc_middle/src/ty/fold.rs272
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs4
-rw-r--r--compiler/rustc_middle/src/ty/visit.rs338
3 files changed, 322 insertions, 292 deletions
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index c0d319edf76..1b8f6e12c3f 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -48,161 +48,173 @@ use rustc_hir::def_id::DefId;
 
 use std::collections::BTreeMap;
 
-/// This trait is implemented for every type that can be folded,
-/// providing the skeleton of the traversal.
-///
-/// To implement this conveniently, use the derive macro located in
-/// `rustc_macros`.
-pub trait TypeFoldable<'tcx>: TypeVisitable<'tcx> {
-    /// The entry point for folding. To fold a value `t` with a folder `f`
-    /// call: `t.try_fold_with(f)`.
-    ///
-    /// For most types, this just traverses the value, calling `try_fold_with`
-    /// on each field/element.
-    ///
-    /// For types of interest (such as `Ty`), the implementation of method
-    /// calls a folder method specifically for that type (such as
-    /// `F::try_fold_ty`). This is where control transfers from `TypeFoldable`
-    /// to `TypeFolder`.
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error>;
-
-    /// A convenient alternative to `try_fold_with` for use with infallible
-    /// folders. Do not override this method, to ensure coherence with
-    /// `try_fold_with`.
-    fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
-        self.try_fold_with(folder).into_ok()
-    }
-}
+pub use ir::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
 
-// This trait is implemented for types of interest.
-pub trait TypeSuperFoldable<'tcx>: TypeFoldable<'tcx> {
-    /// Provides a default fold for a type of interest. This should only be
-    /// called within `TypeFolder` methods, when a non-custom traversal is
-    /// desired for the value of the type of interest passed to that method.
-    /// For example, in `MyFolder::try_fold_ty(ty)`, it is valid to call
-    /// `ty.try_super_fold_with(self)`, but any other folding should be done
-    /// with `xyz.try_fold_with(self)`.
-    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error>;
-
-    /// A convenient alternative to `try_super_fold_with` for use with
-    /// infallible folders. Do not override this method, to ensure coherence
-    /// with `try_super_fold_with`.
-    fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
-        self.try_super_fold_with(folder).into_ok()
-    }
-}
+pub mod ir {
+    use crate::ty::{self, ir::TypeVisitable, Binder, Ty, TyCtxt};
 
-/// This trait is implemented for every infallible folding traversal. There is
-/// a fold method defined for every type of interest. Each such method has a
-/// default that does an "identity" fold. Implementations of these methods
-/// often fall back to a `super_fold_with` method if the primary argument
-/// doesn't satisfy a particular condition.
-///
-/// A blanket implementation of [`FallibleTypeFolder`] will defer to
-/// the infallible methods of this trait to ensure that the two APIs
-/// are coherent.
-pub trait TypeFolder<'tcx>: FallibleTypeFolder<'tcx, Error = !> {
-    fn tcx(&self) -> TyCtxt<'tcx>;
-
-    fn fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T>
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        t.super_fold_with(self)
-    }
-
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        t.super_fold_with(self)
+    /// This trait is implemented for every type that can be folded,
+    /// providing the skeleton of the traversal.
+    ///
+    /// To implement this conveniently, use the derive macro located in
+    /// `rustc_macros`.
+    pub trait TypeFoldable<'tcx>: TypeVisitable<'tcx> {
+        /// The entry point for folding. To fold a value `t` with a folder `f`
+        /// call: `t.try_fold_with(f)`.
+        ///
+        /// For most types, this just traverses the value, calling `try_fold_with`
+        /// on each field/element.
+        ///
+        /// For types of interest (such as `Ty`), the implementation of method
+        /// calls a folder method specifically for that type (such as
+        /// `F::try_fold_ty`). This is where control transfers from `TypeFoldable`
+        /// to `TypeFolder`.
+        fn try_fold_with<F: FallibleTypeFolder<'tcx>>(
+            self,
+            folder: &mut F,
+        ) -> Result<Self, F::Error>;
+
+        /// A convenient alternative to `try_fold_with` for use with infallible
+        /// folders. Do not override this method, to ensure coherence with
+        /// `try_fold_with`.
+        fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+            self.try_fold_with(folder).into_ok()
+        }
     }
 
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        r.super_fold_with(self)
+    // This trait is implemented for types of interest.
+    pub trait TypeSuperFoldable<'tcx>: TypeFoldable<'tcx> {
+        /// Provides a default fold for a type of interest. This should only be
+        /// called within `TypeFolder` methods, when a non-custom traversal is
+        /// desired for the value of the type of interest passed to that method.
+        /// For example, in `MyFolder::try_fold_ty(ty)`, it is valid to call
+        /// `ty.try_super_fold_with(self)`, but any other folding should be done
+        /// with `xyz.try_fold_with(self)`.
+        fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
+            self,
+            folder: &mut F,
+        ) -> Result<Self, F::Error>;
+
+        /// A convenient alternative to `try_super_fold_with` for use with
+        /// infallible folders. Do not override this method, to ensure coherence
+        /// with `try_super_fold_with`.
+        fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+            self.try_super_fold_with(folder).into_ok()
+        }
     }
 
-    fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        c.super_fold_with(self)
-    }
+    /// This trait is implemented for every infallible folding traversal. There is
+    /// a fold method defined for every type of interest. Each such method has a
+    /// default that does an "identity" fold. Implementations of these methods
+    /// often fall back to a `super_fold_with` method if the primary argument
+    /// doesn't satisfy a particular condition.
+    ///
+    /// A blanket implementation of [`FallibleTypeFolder`] will defer to
+    /// the infallible methods of this trait to ensure that the two APIs
+    /// are coherent.
+    pub trait TypeFolder<'tcx>: FallibleTypeFolder<'tcx, Error = !> {
+        fn tcx(&self) -> TyCtxt<'tcx>;
+
+        fn fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T>
+        where
+            T: TypeFoldable<'tcx>,
+        {
+            t.super_fold_with(self)
+        }
 
-    fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
-        p.super_fold_with(self)
-    }
-}
+        fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+            t.super_fold_with(self)
+        }
 
-/// This trait is implemented for every folding traversal. There is a fold
-/// method defined for every type of interest. Each such method has a default
-/// that does an "identity" fold.
-///
-/// A blanket implementation of this trait (that defers to the relevant
-/// method of [`TypeFolder`]) is provided for all infallible folders in
-/// order to ensure the two APIs are coherent.
-pub trait FallibleTypeFolder<'tcx>: Sized {
-    type Error;
+        fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+            r.super_fold_with(self)
+        }
 
-    fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
+        fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
+            c.super_fold_with(self)
+        }
 
-    fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error>
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        t.try_super_fold_with(self)
+        fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
+            p.super_fold_with(self)
+        }
     }
 
-    fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
-        t.try_super_fold_with(self)
-    }
+    /// This trait is implemented for every folding traversal. There is a fold
+    /// method defined for every type of interest. Each such method has a default
+    /// that does an "identity" fold.
+    ///
+    /// A blanket implementation of this trait (that defers to the relevant
+    /// method of [`TypeFolder`]) is provided for all infallible folders in
+    /// order to ensure the two APIs are coherent.
+    pub trait FallibleTypeFolder<'tcx>: Sized {
+        type Error;
 
-    fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
-        r.try_super_fold_with(self)
-    }
+        fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
 
-    fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
-        c.try_super_fold_with(self)
-    }
+        fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, Self::Error>
+        where
+            T: TypeFoldable<'tcx>,
+        {
+            t.try_super_fold_with(self)
+        }
 
-    fn try_fold_predicate(
-        &mut self,
-        p: ty::Predicate<'tcx>,
-    ) -> Result<ty::Predicate<'tcx>, Self::Error> {
-        p.try_super_fold_with(self)
-    }
-}
+        fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
+            t.try_super_fold_with(self)
+        }
 
-// This blanket implementation of the fallible trait for infallible folders
-// delegates to infallible methods to ensure coherence.
-impl<'tcx, F> FallibleTypeFolder<'tcx> for F
-where
-    F: TypeFolder<'tcx>,
-{
-    type Error = !;
+        fn try_fold_region(
+            &mut self,
+            r: ty::Region<'tcx>,
+        ) -> Result<ty::Region<'tcx>, Self::Error> {
+            r.try_super_fold_with(self)
+        }
 
-    fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
-        TypeFolder::tcx(self)
+        fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
+            c.try_super_fold_with(self)
+        }
+
+        fn try_fold_predicate(
+            &mut self,
+            p: ty::Predicate<'tcx>,
+        ) -> Result<ty::Predicate<'tcx>, Self::Error> {
+            p.try_super_fold_with(self)
+        }
     }
 
-    fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, !>
+    // This blanket implementation of the fallible trait for infallible folders
+    // delegates to infallible methods to ensure coherence.
+    impl<'tcx, F> FallibleTypeFolder<'tcx> for F
     where
-        T: TypeFoldable<'tcx>,
+        F: TypeFolder<'tcx>,
     {
-        Ok(self.fold_binder(t))
-    }
+        type Error = !;
 
-    fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, !> {
-        Ok(self.fold_ty(t))
-    }
+        fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
+            TypeFolder::tcx(self)
+        }
 
-    fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, !> {
-        Ok(self.fold_region(r))
-    }
+        fn try_fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Result<Binder<'tcx, T>, !>
+        where
+            T: TypeFoldable<'tcx>,
+        {
+            Ok(self.fold_binder(t))
+        }
 
-    fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, !> {
-        Ok(self.fold_const(c))
-    }
+        fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, !> {
+            Ok(self.fold_ty(t))
+        }
+
+        fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, !> {
+            Ok(self.fold_region(r))
+        }
+
+        fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, !> {
+            Ok(self.fold_const(c))
+        }
 
-    fn try_fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> Result<ty::Predicate<'tcx>, !> {
-        Ok(self.fold_predicate(p))
+        fn try_fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> Result<ty::Predicate<'tcx>, !> {
+            Ok(self.fold_predicate(p))
+        }
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index fa2d3b89cf4..f378c6fd8ad 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -146,6 +146,10 @@ mod structural_impls;
 mod sty;
 mod typeck_results;
 
+pub mod ir {
+    pub use super::{fold::ir::*, visit::ir::*};
+}
+
 // Data types
 
 pub type RegisteredTools = FxHashSet<Ident>;
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
index d7b7a094737..fe3fc4c88c5 100644
--- a/compiler/rustc_middle/src/ty/visit.rs
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -39,189 +39,203 @@
 //! - u.visit_with(visitor)
 //! ```
 use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags};
-use rustc_errors::ErrorGuaranteed;
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sso::SsoHashSet;
-use std::fmt;
 use std::ops::ControlFlow;
 
-/// This trait is implemented for every type that can be visited,
-/// providing the skeleton of the traversal.
-///
-/// To implement this conveniently, use the derive macro located in
-/// `rustc_macros`.
-pub trait TypeVisitable<'tcx>: fmt::Debug + Clone {
-    /// The entry point for visiting. To visit a value `t` with a visitor `v`
-    /// call: `t.visit_with(v)`.
-    ///
-    /// For most types, this just traverses the value, calling `visit_with` on
-    /// each field/element.
-    ///
-    /// For types of interest (such as `Ty`), the implementation of this method
-    /// that calls a visitor method specifically for that type (such as
-    /// `V::visit_ty`). This is where control transfers from `TypeFoldable` to
-    /// `TypeVisitor`.
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
-
-    /// Returns `true` if `self` has any late-bound regions that are either
-    /// bound by `binder` or bound by some binder outside of `binder`.
-    /// If `binder` is `ty::INNERMOST`, this indicates whether
-    /// there are any late-bound regions that appear free.
-    fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
-        self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }).is_break()
-    }
-
-    /// Returns `true` if this type has any regions that escape `binder` (and
-    /// hence are not bound by it).
-    fn has_vars_bound_above(&self, binder: ty::DebruijnIndex) -> bool {
-        self.has_vars_bound_at_or_above(binder.shifted_in(1))
-    }
-
-    /// Return `true` if this type has regions that are not a part of the type.
-    /// For example, `for<'a> fn(&'a i32)` return `false`, while `fn(&'a i32)`
-    /// would return `true`. The latter can occur when traversing through the
-    /// former.
+pub use ir::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
+
+pub mod ir {
+    use crate::ty::{self, Binder, Ty, TypeFlags};
+    use rustc_errors::ErrorGuaranteed;
+
+    use std::fmt;
+    use std::ops::ControlFlow;
+
+    use super::{FoundFlags, HasEscapingVarsVisitor, HasTypeFlagsVisitor};
+
+    /// This trait is implemented for every type that can be visited,
+    /// providing the skeleton of the traversal.
     ///
-    /// See [`HasEscapingVarsVisitor`] for more information.
-    fn has_escaping_bound_vars(&self) -> bool {
-        self.has_vars_bound_at_or_above(ty::INNERMOST)
-    }
+    /// To implement this conveniently, use the derive macro located in
+    /// `rustc_macros`.
+    pub trait TypeVisitable<'tcx>: fmt::Debug + Clone {
+        /// The entry point for visiting. To visit a value `t` with a visitor `v`
+        /// call: `t.visit_with(v)`.
+        ///
+        /// For most types, this just traverses the value, calling `visit_with` on
+        /// each field/element.
+        ///
+        /// For types of interest (such as `Ty`), the implementation of this method
+        /// that calls a visitor method specifically for that type (such as
+        /// `V::visit_ty`). This is where control transfers from `TypeFoldable` to
+        /// `TypeVisitor`.
+        fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
+
+        /// Returns `true` if `self` has any late-bound regions that are either
+        /// bound by `binder` or bound by some binder outside of `binder`.
+        /// If `binder` is `ty::INNERMOST`, this indicates whether
+        /// there are any late-bound regions that appear free.
+        fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
+            self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }).is_break()
+        }
 
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        let res =
-            self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags);
-        trace!(?self, ?flags, ?res, "has_type_flags");
-        res
-    }
-    fn has_projections(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_PROJECTION)
-    }
-    fn has_opaque_types(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_TY_OPAQUE)
-    }
-    fn has_generators(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_TY_GENERATOR)
-    }
-    fn references_error(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_ERROR)
-    }
-    fn error_reported(&self) -> Result<(), ErrorGuaranteed> {
-        if self.references_error() {
-            if let Some(reported) = ty::tls::with(|tcx| tcx.sess.is_compilation_going_to_fail()) {
-                Err(reported)
+        /// Returns `true` if this type has any regions that escape `binder` (and
+        /// hence are not bound by it).
+        fn has_vars_bound_above(&self, binder: ty::DebruijnIndex) -> bool {
+            self.has_vars_bound_at_or_above(binder.shifted_in(1))
+        }
+
+        /// Return `true` if this type has regions that are not a part of the type.
+        /// For example, `for<'a> fn(&'a i32)` return `false`, while `fn(&'a i32)`
+        /// would return `true`. The latter can occur when traversing through the
+        /// former.
+        ///
+        /// See [`HasEscapingVarsVisitor`] for more information.
+        fn has_escaping_bound_vars(&self) -> bool {
+            self.has_vars_bound_at_or_above(ty::INNERMOST)
+        }
+
+        fn has_type_flags(&self, flags: TypeFlags) -> bool {
+            let res = self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value()
+                == Some(FoundFlags);
+            trace!(?self, ?flags, ?res, "has_type_flags");
+            res
+        }
+        fn has_projections(&self) -> bool {
+            self.has_type_flags(TypeFlags::HAS_PROJECTION)
+        }
+        fn has_opaque_types(&self) -> bool {
+            self.has_type_flags(TypeFlags::HAS_TY_OPAQUE)
+        }
+        fn has_generators(&self) -> bool {
+            self.has_type_flags(TypeFlags::HAS_TY_GENERATOR)
+        }
+        fn references_error(&self) -> bool {
+            self.has_type_flags(TypeFlags::HAS_ERROR)
+        }
+        fn error_reported(&self) -> Result<(), ErrorGuaranteed> {
+            if self.references_error() {
+                if let Some(reported) = ty::tls::with(|tcx| tcx.sess.is_compilation_going_to_fail())
+                {
+                    Err(reported)
+                } else {
+                    bug!("expect tcx.sess.is_compilation_going_to_fail return `Some`");
+                }
             } else {
-                bug!("expect tcx.sess.is_compilation_going_to_fail return `Some`");
+                Ok(())
             }
-        } else {
-            Ok(())
         }
-    }
-    fn has_non_region_param(&self) -> bool {
-        self.has_type_flags(TypeFlags::NEEDS_SUBST - TypeFlags::HAS_RE_PARAM)
-    }
-    fn has_infer_regions(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_RE_INFER)
-    }
-    fn has_infer_types(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_TY_INFER)
-    }
-    fn has_non_region_infer(&self) -> bool {
-        self.has_type_flags(TypeFlags::NEEDS_INFER - TypeFlags::HAS_RE_INFER)
-    }
-    fn needs_infer(&self) -> bool {
-        self.has_type_flags(TypeFlags::NEEDS_INFER)
-    }
-    fn has_placeholders(&self) -> bool {
-        self.has_type_flags(
-            TypeFlags::HAS_RE_PLACEHOLDER
-                | TypeFlags::HAS_TY_PLACEHOLDER
-                | TypeFlags::HAS_CT_PLACEHOLDER,
-        )
-    }
-    fn needs_subst(&self) -> bool {
-        self.has_type_flags(TypeFlags::NEEDS_SUBST)
-    }
-    /// "Free" regions in this context means that it has any region
-    /// that is not (a) erased or (b) late-bound.
-    fn has_free_regions(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
-    }
+        fn has_non_region_param(&self) -> bool {
+            self.has_type_flags(TypeFlags::NEEDS_SUBST - TypeFlags::HAS_RE_PARAM)
+        }
+        fn has_infer_regions(&self) -> bool {
+            self.has_type_flags(TypeFlags::HAS_RE_INFER)
+        }
+        fn has_infer_types(&self) -> bool {
+            self.has_type_flags(TypeFlags::HAS_TY_INFER)
+        }
+        fn has_non_region_infer(&self) -> bool {
+            self.has_type_flags(TypeFlags::NEEDS_INFER - TypeFlags::HAS_RE_INFER)
+        }
+        fn needs_infer(&self) -> bool {
+            self.has_type_flags(TypeFlags::NEEDS_INFER)
+        }
+        fn has_placeholders(&self) -> bool {
+            self.has_type_flags(
+                TypeFlags::HAS_RE_PLACEHOLDER
+                    | TypeFlags::HAS_TY_PLACEHOLDER
+                    | TypeFlags::HAS_CT_PLACEHOLDER,
+            )
+        }
+        fn needs_subst(&self) -> bool {
+            self.has_type_flags(TypeFlags::NEEDS_SUBST)
+        }
+        /// "Free" regions in this context means that it has any region
+        /// that is not (a) erased or (b) late-bound.
+        fn has_free_regions(&self) -> bool {
+            self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
+        }
 
-    fn has_erased_regions(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_RE_ERASED)
-    }
+        fn has_erased_regions(&self) -> bool {
+            self.has_type_flags(TypeFlags::HAS_RE_ERASED)
+        }
 
-    /// True if there are any un-erased free regions.
-    fn has_erasable_regions(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
-    }
+        /// True if there are any un-erased free regions.
+        fn has_erasable_regions(&self) -> bool {
+            self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
+        }
 
-    /// Indicates whether this value references only 'global'
-    /// generic parameters that are the same regardless of what fn we are
-    /// in. This is used for caching.
-    fn is_global(&self) -> bool {
-        !self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES)
-    }
+        /// Indicates whether this value references only 'global'
+        /// generic parameters that are the same regardless of what fn we are
+        /// in. This is used for caching.
+        fn is_global(&self) -> bool {
+            !self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES)
+        }
 
-    /// True if there are any late-bound regions
-    fn has_late_bound_regions(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND)
-    }
-    /// True if there are any late-bound non-region variables
-    fn has_non_region_late_bound(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_LATE_BOUND - TypeFlags::HAS_RE_LATE_BOUND)
-    }
-    /// True if there are any late-bound variables
-    fn has_late_bound_vars(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_LATE_BOUND)
-    }
+        /// True if there are any late-bound regions
+        fn has_late_bound_regions(&self) -> bool {
+            self.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND)
+        }
+        /// True if there are any late-bound non-region variables
+        fn has_non_region_late_bound(&self) -> bool {
+            self.has_type_flags(TypeFlags::HAS_LATE_BOUND - TypeFlags::HAS_RE_LATE_BOUND)
+        }
+        /// True if there are any late-bound variables
+        fn has_late_bound_vars(&self) -> bool {
+            self.has_type_flags(TypeFlags::HAS_LATE_BOUND)
+        }
 
-    /// Indicates whether this value still has parameters/placeholders/inference variables
-    /// which could be replaced later, in a way that would change the results of `impl`
-    /// specialization.
-    fn still_further_specializable(&self) -> bool {
-        self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE)
+        /// Indicates whether this value still has parameters/placeholders/inference variables
+        /// which could be replaced later, in a way that would change the results of `impl`
+        /// specialization.
+        fn still_further_specializable(&self) -> bool {
+            self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE)
+        }
     }
-}
-
-pub trait TypeSuperVisitable<'tcx>: TypeVisitable<'tcx> {
-    /// Provides a default visit for a type of interest. This should only be
-    /// called within `TypeVisitor` methods, when a non-custom traversal is
-    /// desired for the value of the type of interest passed to that method.
-    /// For example, in `MyVisitor::visit_ty(ty)`, it is valid to call
-    /// `ty.super_visit_with(self)`, but any other visiting should be done
-    /// with `xyz.visit_with(self)`.
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
-}
-
-/// This trait is implemented for every visiting traversal. There is a visit
-/// method defined for every type of interest. Each such method has a default
-/// that recurses into the type's fields in a non-custom fashion.
-pub trait TypeVisitor<'tcx>: Sized {
-    type BreakTy = !;
 
-    fn visit_binder<T: TypeVisitable<'tcx>>(
-        &mut self,
-        t: &Binder<'tcx, T>,
-    ) -> ControlFlow<Self::BreakTy> {
-        t.super_visit_with(self)
-    }
+    pub trait TypeSuperVisitable<'tcx>: TypeVisitable<'tcx> {
+        /// Provides a default visit for a type of interest. This should only be
+        /// called within `TypeVisitor` methods, when a non-custom traversal is
+        /// desired for the value of the type of interest passed to that method.
+        /// For example, in `MyVisitor::visit_ty(ty)`, it is valid to call
+        /// `ty.super_visit_with(self)`, but any other visiting should be done
+        /// with `xyz.visit_with(self)`.
+        fn super_visit_with<V: TypeVisitor<'tcx>>(
+            &self,
+            visitor: &mut V,
+        ) -> ControlFlow<V::BreakTy>;
+    }
+
+    /// This trait is implemented for every visiting traversal. There is a visit
+    /// method defined for every type of interest. Each such method has a default
+    /// that recurses into the type's fields in a non-custom fashion.
+    pub trait TypeVisitor<'tcx>: Sized {
+        type BreakTy = !;
+
+        fn visit_binder<T: TypeVisitable<'tcx>>(
+            &mut self,
+            t: &Binder<'tcx, T>,
+        ) -> ControlFlow<Self::BreakTy> {
+            t.super_visit_with(self)
+        }
 
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-        t.super_visit_with(self)
-    }
+        fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+            t.super_visit_with(self)
+        }
 
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
-        r.super_visit_with(self)
-    }
+        fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+            r.super_visit_with(self)
+        }
 
-    fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-        c.super_visit_with(self)
-    }
+        fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+            c.super_visit_with(self)
+        }
 
-    fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
-        p.super_visit_with(self)
+        fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
+            p.super_visit_with(self)
+        }
     }
 }