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.
26- //!
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.
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.
3341use crate :: mir;
3442use crate :: ty:: { self , flags:: FlagComputation , Binder , Ty , TyCtxt , TypeFlags } ;
35- use rustc_hir as hir;
3643use rustc_hir:: def_id:: DefId ;
3744
3845use rustc_data_structures:: fx:: FxHashSet ;
@@ -41,42 +48,67 @@ use std::collections::BTreeMap;
4148use std:: fmt;
4249use std:: ops:: ControlFlow ;
4350
44- /// This trait is implemented for every type that can be folded.
45- /// Basically, every type that has a corresponding method in `TypeFolder` .
51+ /// This trait is implemented for every type that can be folded/visited,
52+ /// providing the skeleton of the traversal .
4653///
47- /// To implement this conveniently, use the derive macro located in `rustc_macros`.
54+ /// To implement this conveniently, use the derive macro located in
55+ /// `rustc_macros`.
4856pub 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 ( )
57+ /// The main entry point for folding. To fold a value `t` with a folder `f`
58+ /// call: `t.try_fold_with(f)`.
59+ ///
60+ /// For types of interest (such as `Ty`), this default is overridden with a
61+ /// method that calls a folder method specifically for that type (such as
62+ /// `F::try_fold_ty`). This is where control transfers from `TypeFoldable`
63+ /// to `TypeFolder`.
64+ ///
65+ /// For other types, this default is used.
66+ fn try_fold_with < F : FallibleTypeFolder < ' tcx > > ( self , folder : & mut F ) -> Result < Self , F :: Error > {
67+ self . try_super_fold_with ( folder)
5668 }
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).
69+
70+ /// A convenient alternative to [`try_fold_with`] for use with infallible
71+ /// folders. Do not override this method, to ensure coherence with
72+ /// `try_fold_with`.
6273 fn fold_with < F : TypeFolder < ' tcx , Error = !> > ( self , folder : & mut F ) -> Self {
6374 self . try_fold_with ( folder) . into_ok ( )
6475 }
6576
77+ /// Traverses the type in question, typically by calling `try_fold_with` on
78+ /// each field/element. This is true even for types of interest such as
79+ /// `Ty`. This should only be called within `TypeFolder` methods, when
80+ /// non-custom traversals are desired for types of interest.
6681 fn try_super_fold_with < F : FallibleTypeFolder < ' tcx > > (
6782 self ,
6883 folder : & mut F ,
6984 ) -> Result < Self , F :: Error > ;
7085
71- fn try_fold_with < F : FallibleTypeFolder < ' tcx > > ( self , folder : & mut F ) -> Result < Self , F :: Error > {
72- self . try_super_fold_with ( folder)
86+ /// A convenient alternative to [`try_super_fold_with`] for use with
87+ /// infallible folders. Do not override this method, to ensure coherence
88+ /// with `try_super_fold_with`.
89+ fn super_fold_with < F : TypeFolder < ' tcx , Error = !> > ( self , folder : & mut F ) -> Self {
90+ self . try_super_fold_with ( folder) . into_ok ( )
7391 }
7492
75- fn super_visit_with < V : TypeVisitor < ' tcx > > ( & self , visitor : & mut V ) -> ControlFlow < V :: BreakTy > ;
93+ /// The entry point for visiting. To visit a value `t` with a visitor `v`
94+ /// call: `t.visit_with(v)`.
95+ ///
96+ /// For types of interest (such as `Ty`), this default is overridden with a
97+ /// method that calls a visitor method specifically for that type (such as
98+ /// `V::visit_ty`). This is where control transfers from `TypeFoldable` to
99+ /// `TypeFolder`.
100+ ///
101+ /// For other types, this default is used.
76102 fn visit_with < V : TypeVisitor < ' tcx > > ( & self , visitor : & mut V ) -> ControlFlow < V :: BreakTy > {
77103 self . super_visit_with ( visitor)
78104 }
79105
106+ /// Traverses the type in question, typically by calling `visit_with` on
107+ /// each field/element. This is true even for types of interest such as
108+ /// `Ty`. This should only be called within `TypeVisitor` methods, when
109+ /// non-custom traversals are desired for types of interest.
110+ fn super_visit_with < V : TypeVisitor < ' tcx > > ( & self , visitor : & mut V ) -> ControlFlow < V :: BreakTy > ;
111+
80112 /// Returns `true` if `self` has any late-bound regions that are either
81113 /// bound by `binder` or bound by some binder outside of `binder`.
82114 /// If `binder` is `ty::INNERMOST`, this indicates whether
@@ -168,24 +200,13 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
168200 }
169201}
170202
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.
203+ /// This trait is implemented for every folding traversal. There is a fold
204+ /// method defined for every type of interest. Each such method has a default
205+ /// that does an "identity" fold.
185206///
186207/// 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 ,
208+ /// associated type is something other than the default `!`) then
209+ /// [`FallibleTypeFolder`] should be implemented manually. Otherwise ,
189210/// a blanket implementation of [`FallibleTypeFolder`] will defer to
190211/// the infallible methods of this trait to ensure that the two APIs
191212/// are coherent.
@@ -238,11 +259,9 @@ pub trait TypeFolder<'tcx>: Sized {
238259 }
239260}
240261
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.
262+ /// This trait is implemented for every folding traversal. There is a fold
263+ /// method defined for every type of interest. Each such method has a default
264+ /// that does an "identity" fold.
246265///
247266/// A blanket implementation of this trait (that defers to the relevant
248267/// method of [`TypeFolder`]) is provided for all infallible folders in
@@ -285,8 +304,8 @@ pub trait FallibleTypeFolder<'tcx>: TypeFolder<'tcx> {
285304 }
286305}
287306
288- // Blanket implementation of fallible trait for infallible folders
289- // delegates to infallible methods to prevent incoherence
307+ // This blanket implementation of the fallible trait for infallible folders
308+ // delegates to infallible methods to ensure coherence.
290309impl < ' tcx , F > FallibleTypeFolder < ' tcx > for F
291310where
292311 F : TypeFolder < ' tcx , Error = !> ,
@@ -328,6 +347,9 @@ where
328347 }
329348}
330349
350+ /// This trait is implemented for every visiting traversal. There is a visit
351+ /// method defined for every type of interest. Each such method has a default
352+ /// that does a non-custom visit.
331353pub trait TypeVisitor < ' tcx > : Sized {
332354 type BreakTy = !;
333355
0 commit comments