1- //! Generalized type folding mechanism. The setup is a bit convoluted
2- //! but allows for convenient usage. Let T be an instance of some
3- //! "foldable type" (one which implements `TypeFoldable`) and F be an
4- //! instance of a "folder" (a type which implements `TypeFolder`). Then
5- //! the setup is intended to be:
1+ //! A generalized traversal mechanism for complex data structures that contain
2+ //! type information.
63//!
7- //! T.fold_with(F) --calls--> F.fold_T(T) --calls--> T.super_fold_with(F)
4+ //! There are two types of traversal.
5+ //! - Folding. This is a modifying traversal. It consumes the data structure,
6+ //! producing a (possibly) modified version of it. Both fallible and
7+ //! infallible versions are available. The name is potentially
8+ //! confusing, because this traversal is more like `Iterator::map` than
9+ //! `Iterator::fold`.
10+ //! - Visiting. This is a read-only traversal of the data structure.
811//!
9- //! This way, when you define a new folder F, you can override
10- //! `fold_T()` to customize the behavior, and invoke `T.super_fold_with()`
11- //! to get the original behavior. Meanwhile, to actually fold
12- //! something, you can just write `T.fold_with(F)`, which is
13- //! convenient. (Note that `fold_with` will also transparently handle
14- //! things like a `Vec<T>` where T is foldable and so on.)
12+ //! These traversals have limited flexibility. Only a small number of "types of
13+ //! interest" within the complex data structures can receive custom
14+ //! modification (when folding) or custom visitation (when visiting). These are
15+ //! the ones containing the most important type-related information, such as
16+ //! `Ty`, `Predicate`, `Region`, and `Const`.
1517//!
16- //! In this ideal setup, the only function that actually *does*
17- //! anything is `T.super_fold_with()`, which traverses the type `T`.
18- //! Moreover, `T.super_fold_with()` should only ever call `T.fold_with()`.
18+ //! There are two traits involved in each traversal type.
19+ //! - The first trait is `TypeFoldable`, which is implemented once for many
20+ //! types. This includes both (a) types of interest, and (b) all other
21+ //! relevant types, including generic containers like `Vec` and `Option`. It
22+ //! defines a "skeleton" of how they should be traversed, for both folding
23+ //! and visiting.
24+ //! - The second trait is `TypeFolder`/`FallibleTypeFolder` (for
25+ //! infallible/fallible folding traversals) or `TypeVisitor` (for visiting
26+ //! traversals). One of these is implemented for each folder/visitor. This
27+ //! defines how types of interest are handled.
1928//!
20- //! In some cases, we follow a degenerate pattern where we do not have
21- //! a `fold_T` method. Instead, `T.fold_with` traverses the structure directly.
22- //! This is suboptimal because the behavior cannot be overridden, but it's
23- //! much less work to implement. If you ever *do* need an override that
24- //! doesn't exist, it's not hard to convert the degenerate pattern into the
25- //! proper thing.
29+ //! This means each traversal is a mixture of (a) generic traversal operations,
30+ //! and (b) custom fold/visit operations that are specific to the
31+ //! folder/visitor.
32+ //! - The `TypeFoldable` impls handle most of the traversal, and call into
33+ //! `TypeFolder`/`FallibleTypeFolder`/`TypeVisitor` when they encounter a
34+ //! type of interest.
35+ //! - A `TypeFolder`/`FallibleTypeFolder`/`TypeVisitor` may also call back into
36+ //! a `TypeFoldable` impl, because (a) the types of interest are recursive
37+ //! and can contain other types of interest, and (b) each folder/visitor
38+ //! might provide custom handling only for some types of interest, or only
39+ //! for some variants of each type of interest, and then use default
40+ //! traversal for the remaining cases.
2641//!
27- //! A `TypeFoldable` T can also be visited by a `TypeVisitor` V using similar setup:
28- //!
29- //! T.visit_with(V) --calls--> V.visit_T(T) --calls--> T.super_visit_with(V).
30- //!
31- //! These methods return true to indicate that the visitor has found what it is
32- //! looking for, and does not need to visit anything else.
42+ //! For example, if you have `struct S(Ty, U)` where `S: TypeFoldable` and `U:
43+ //! TypeFoldable`, and an instance `S(ty, u)`, it would be visited like so:
44+ //! ```
45+ //! s.visit_with(visitor) calls
46+ //! - s.super_visit_with(visitor) calls
47+ //! - ty.visit_with(visitor) calls
48+ //! - visitor.visit_ty(ty) may call
49+ //! - ty.super_visit_with(visitor)
50+ //! - u.visit_with(visitor)
51+ //! ```
3352use crate :: mir;
3453use crate :: ty:: { self , flags:: FlagComputation , Binder , Ty , TyCtxt , TypeFlags } ;
35- use rustc_hir as hir;
3654use rustc_hir:: def_id:: DefId ;
3755
3856use rustc_data_structures:: fx:: FxHashSet ;
@@ -41,42 +59,67 @@ use std::collections::BTreeMap;
4159use std:: fmt;
4260use std:: ops:: ControlFlow ;
4361
44- /// This trait is implemented for every type that can be folded.
45- /// Basically, every type that has a corresponding method in `TypeFolder` .
62+ /// This trait is implemented for every type that can be folded/visited,
63+ /// providing the skeleton of the traversal .
4664///
47- /// To implement this conveniently, use the derive macro located in `rustc_macros`.
65+ /// To implement this conveniently, use the derive macro located in
66+ /// `rustc_macros`.
4867pub trait TypeFoldable < ' tcx > : fmt:: Debug + Clone {
49- /// Consumers may find this more convenient to use with infallible folders than
50- /// [`try_super_fold_with`][`TypeFoldable::try_super_fold_with`], to which the
51- /// provided default definition delegates. Implementors **should not** override
52- /// this provided default definition, to ensure that the two methods are coherent
53- /// (provide a definition of `try_super_fold_with` instead).
54- fn super_fold_with < F : TypeFolder < ' tcx , Error = !> > ( self , folder : & mut F ) -> Self {
55- self . try_super_fold_with ( folder) . into_ok ( )
68+ /// The main entry point for folding. To fold a value `t` with a folder `f`
69+ /// call: `t.try_fold_with(f)`.
70+ ///
71+ /// For types of interest (such as `Ty`), this default is overridden with a
72+ /// method that calls a folder method specifically for that type (such as
73+ /// `F::try_fold_ty`). This is where control transfers from `TypeFoldable`
74+ /// to `TypeFolder`.
75+ ///
76+ /// For other types, this default is used.
77+ fn try_fold_with < F : FallibleTypeFolder < ' tcx > > ( self , folder : & mut F ) -> Result < Self , F :: Error > {
78+ self . try_super_fold_with ( folder)
5679 }
57- /// Consumers may find this more convenient to use with infallible folders than
58- /// [`try_fold_with`][`TypeFoldable::try_fold_with`], to which the provided
59- /// default definition delegates. Implementors **should not** override this
60- /// provided default definition, to ensure that the two methods are coherent
61- /// (provide a definition of `try_fold_with` instead).
80+
81+ /// A convenient alternative to `try_fold_with` for use with infallible
82+ /// folders. Do not override this method, to ensure coherence with
83+ /// `try_fold_with`.
6284 fn fold_with < F : TypeFolder < ' tcx , Error = !> > ( self , folder : & mut F ) -> Self {
6385 self . try_fold_with ( folder) . into_ok ( )
6486 }
6587
88+ /// Traverses the type in question, typically by calling `try_fold_with` on
89+ /// each field/element. This is true even for types of interest such as
90+ /// `Ty`. This should only be called within `TypeFolder` methods, when
91+ /// non-custom traversals are desired for types of interest.
6692 fn try_super_fold_with < F : FallibleTypeFolder < ' tcx > > (
6793 self ,
6894 folder : & mut F ,
6995 ) -> Result < Self , F :: Error > ;
7096
71- fn try_fold_with < F : FallibleTypeFolder < ' tcx > > ( self , folder : & mut F ) -> Result < Self , F :: Error > {
72- self . try_super_fold_with ( folder)
97+ /// A convenient alternative to `try_super_fold_with` for use with
98+ /// infallible folders. Do not override this method, to ensure coherence
99+ /// with `try_super_fold_with`.
100+ fn super_fold_with < F : TypeFolder < ' tcx , Error = !> > ( self , folder : & mut F ) -> Self {
101+ self . try_super_fold_with ( folder) . into_ok ( )
73102 }
74103
75- fn super_visit_with < V : TypeVisitor < ' tcx > > ( & self , visitor : & mut V ) -> ControlFlow < V :: BreakTy > ;
104+ /// The entry point for visiting. To visit a value `t` with a visitor `v`
105+ /// call: `t.visit_with(v)`.
106+ ///
107+ /// For types of interest (such as `Ty`), this default is overridden with a
108+ /// method that calls a visitor method specifically for that type (such as
109+ /// `V::visit_ty`). This is where control transfers from `TypeFoldable` to
110+ /// `TypeVisitor`.
111+ ///
112+ /// For other types, this default is used.
76113 fn visit_with < V : TypeVisitor < ' tcx > > ( & self , visitor : & mut V ) -> ControlFlow < V :: BreakTy > {
77114 self . super_visit_with ( visitor)
78115 }
79116
117+ /// Traverses the type in question, typically by calling `visit_with` on
118+ /// each field/element. This is true even for types of interest such as
119+ /// `Ty`. This should only be called within `TypeVisitor` methods, when
120+ /// non-custom traversals are desired for types of interest.
121+ fn super_visit_with < V : TypeVisitor < ' tcx > > ( & self , visitor : & mut V ) -> ControlFlow < V :: BreakTy > ;
122+
80123 /// Returns `true` if `self` has any late-bound regions that are either
81124 /// bound by `binder` or bound by some binder outside of `binder`.
82125 /// If `binder` is `ty::INNERMOST`, this indicates whether
@@ -168,24 +211,13 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
168211 }
169212}
170213
171- impl < ' tcx > TypeFoldable < ' tcx > for hir:: Constness {
172- fn try_super_fold_with < F : TypeFolder < ' tcx > > ( self , _: & mut F ) -> Result < Self , F :: Error > {
173- Ok ( self )
174- }
175- fn super_visit_with < V : TypeVisitor < ' tcx > > ( & self , _: & mut V ) -> ControlFlow < V :: BreakTy > {
176- ControlFlow :: CONTINUE
177- }
178- }
179-
180- /// The `TypeFolder` trait defines the actual *folding*. There is a
181- /// method defined for every foldable type. Each of these has a
182- /// default implementation that does an "identity" fold. Within each
183- /// identity fold, it should invoke `foo.fold_with(self)` to fold each
184- /// sub-item.
214+ /// This trait is implemented for every folding traversal. There is a fold
215+ /// method defined for every type of interest. Each such method has a default
216+ /// that does an "identity" fold.
185217///
186218/// If this folder is fallible (and therefore its [`Error`][`TypeFolder::Error`]
187- /// associated type is something other than the default, never),
188- /// [`FallibleTypeFolder`] should be implemented manually; otherwise ,
219+ /// associated type is something other than the default `!`) then
220+ /// [`FallibleTypeFolder`] should be implemented manually. Otherwise ,
189221/// a blanket implementation of [`FallibleTypeFolder`] will defer to
190222/// the infallible methods of this trait to ensure that the two APIs
191223/// are coherent.
@@ -238,11 +270,9 @@ pub trait TypeFolder<'tcx>: Sized {
238270 }
239271}
240272
241- /// The `FallibleTypeFolder` trait defines the actual *folding*. There is a
242- /// method defined for every foldable type. Each of these has a
243- /// default implementation that does an "identity" fold. Within each
244- /// identity fold, it should invoke `foo.try_fold_with(self)` to fold each
245- /// sub-item.
273+ /// This trait is implemented for every folding traversal. There is a fold
274+ /// method defined for every type of interest. Each such method has a default
275+ /// that does an "identity" fold.
246276///
247277/// A blanket implementation of this trait (that defers to the relevant
248278/// method of [`TypeFolder`]) is provided for all infallible folders in
@@ -282,8 +312,8 @@ pub trait FallibleTypeFolder<'tcx>: TypeFolder<'tcx> {
282312 }
283313}
284314
285- // Blanket implementation of fallible trait for infallible folders
286- // delegates to infallible methods to prevent incoherence
315+ // This blanket implementation of the fallible trait for infallible folders
316+ // delegates to infallible methods to ensure coherence.
287317impl < ' tcx , F > FallibleTypeFolder < ' tcx > for F
288318where
289319 F : TypeFolder < ' tcx , Error = !> ,
@@ -322,6 +352,9 @@ where
322352 }
323353}
324354
355+ /// This trait is implemented for every visiting traversal. There is a visit
356+ /// method defined for every type of interest. Each such method has a default
357+ /// that recurses into the type's fields in a non-custom fashion.
325358pub trait TypeVisitor < ' tcx > : Sized {
326359 type BreakTy = !;
327360
0 commit comments