diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 156eda477ade4..fb760654ea785 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -33,14 +33,6 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable> { } fn has_type_flags(&self, flags: TypeFlags) -> bool { - // N.B. Even though this uses a visitor, the visitor does not actually - // recurse through the whole `TypeVisitable` implementor type. - // - // Instead it stops on the first "level", visiting types, regions, - // consts and predicates just fetches their type flags. - // - // Thus this is a lot faster than it might seem and should be - // optimized to a simple field access. let res = self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags); trace!(?self, ?flags, ?res, "has_type_flags"); @@ -485,11 +477,16 @@ impl std::fmt::Debug for HasTypeFlagsVisitor { } } +// Note: this visitor traverses values down to the level of +// `Ty`/`Const`/`Predicate`, but not within those types. This is because the +// type flags at the outer layer are enough. So it's faster than it first +// looks, particular for `Ty`/`Predicate` where it's just a field access. impl<'tcx> TypeVisitor> for HasTypeFlagsVisitor { type BreakTy = FoundFlags; #[inline] fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { + // Note: no `super_visit_with` call. let flags = t.flags(); if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) @@ -500,6 +497,7 @@ impl<'tcx> TypeVisitor> for HasTypeFlagsVisitor { #[inline] fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { + // Note: no `super_visit_with` call, as usual for `Region`. let flags = r.type_flags(); if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) @@ -510,6 +508,7 @@ impl<'tcx> TypeVisitor> for HasTypeFlagsVisitor { #[inline] fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow { + // Note: no `super_visit_with` call. let flags = FlagComputation::for_const(c); trace!(r.flags=?flags); if flags.intersects(self.flags) { @@ -521,6 +520,7 @@ impl<'tcx> TypeVisitor> for HasTypeFlagsVisitor { #[inline] fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow { + // Note: no `super_visit_with` call. if predicate.flags().intersects(self.flags) { ControlFlow::Break(FoundFlags) } else { diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index 371c611912286..e7a6831f5ee35 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -11,7 +11,7 @@ //! modification. These are the ones containing the most important type-related //! information, such as `Ty`, `Predicate`, `Region`, and `Const`. //! -//! There are three groups of traits involved in each traversal. +//! There are three traits involved in each traversal. //! - `TypeFoldable`. This is implemented once for many types, including: //! - Types of interest, for which the methods delegate to the folder. //! - All other types, including generic containers like `Vec` and `Option`. @@ -51,6 +51,12 @@ use crate::{visit::TypeVisitable, Interner}; /// /// To implement this conveniently, use the derive macro located in /// `rustc_macros`. +/// +/// This trait is a sub-trait of `TypeVisitable`. This is because many +/// `TypeFolder` instances use the methods in `TypeVisitableExt` while folding, +/// which means in practice almost every foldable type needs to also be +/// visitable. (However, there are some types that are visitable without being +/// foldable.) pub trait TypeFoldable: TypeVisitable { /// The entry point for folding. To fold a value `t` with a folder `f` /// call: `t.try_fold_with(f)`. @@ -58,7 +64,7 @@ pub trait TypeFoldable: TypeVisitable { /// 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 + /// For types of interest (such as `Ty`), the implementation of this method /// calls a folder method specifically for that type (such as /// `F::try_fold_ty`). This is where control transfers from `TypeFoldable` /// to `TypeFolder`. @@ -121,7 +127,7 @@ pub trait TypeFolder: FallibleTypeFolder { } // The default region folder is a no-op because `Region` is non-recursive - // and has no `super_visit_with` method to call. That also explains the + // and has no `super_fold_with` method to call. That also explains the // lack of `I::Region: TypeSuperFoldable` bound on this method. fn fold_region(&mut self, r: I::Region) -> I::Region { r @@ -170,7 +176,7 @@ pub trait FallibleTypeFolder: Sized { } // The default region folder is a no-op because `Region` is non-recursive - // and has no `super_visit_with` method to call. That also explains the + // and has no `super_fold_with` method to call. That also explains the // lack of `I::Region: TypeSuperFoldable` bound on this method. fn try_fold_region(&mut self, r: I::Region) -> Result { Ok(r) diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 878c7aec6c18e..891a4dda22fef 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -8,7 +8,7 @@ //! visitation. These are the ones containing the most important type-related //! information, such as `Ty`, `Predicate`, `Region`, and `Const`. //! -//! There are three groups of traits involved in each traversal. +//! There are three traits involved in each traversal. //! - `TypeVisitable`. This is implemented once for many types, including: //! - Types of interest, for which the methods delegate to the visitor. //! - All other types, including generic containers like `Vec` and `Option`. @@ -17,7 +17,6 @@ //! interest, and defines the visiting "skeleton" for these types. (This //! excludes `Region` because it is non-recursive, i.e. it never contains //! other types of interest.) -//! //! - `TypeVisitor`. This is implemented for each visitor. This defines how //! types of interest are visited. //! @@ -60,7 +59,7 @@ pub trait TypeVisitable: fmt::Debug + Clone { /// /// 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 + /// `V::visit_ty`). This is where control transfers from `TypeVisitable` to /// `TypeVisitor`. fn visit_with>(&self, visitor: &mut V) -> ControlFlow; }