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.
6
3
//!
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.
8
11
//!
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`.
15
17
//!
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.
19
28
//!
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.
33
41
use crate :: mir;
34
42
use crate :: ty:: { self , flags:: FlagComputation , Binder , Ty , TyCtxt , TypeFlags } ;
35
- use rustc_hir as hir;
36
43
use rustc_hir:: def_id:: DefId ;
37
44
38
45
use rustc_data_structures:: fx:: FxHashSet ;
@@ -41,42 +48,67 @@ use std::collections::BTreeMap;
41
48
use std:: fmt;
42
49
use std:: ops:: ControlFlow ;
43
50
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 .
46
53
///
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`.
48
56
pub 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)
56
68
}
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`.
62
73
fn fold_with < F : TypeFolder < ' tcx , Error = !> > ( self , folder : & mut F ) -> Self {
63
74
self . try_fold_with ( folder) . into_ok ( )
64
75
}
65
76
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.
66
81
fn try_super_fold_with < F : FallibleTypeFolder < ' tcx > > (
67
82
self ,
68
83
folder : & mut F ,
69
84
) -> Result < Self , F :: Error > ;
70
85
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 ( )
73
91
}
74
92
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.
76
102
fn visit_with < V : TypeVisitor < ' tcx > > ( & self , visitor : & mut V ) -> ControlFlow < V :: BreakTy > {
77
103
self . super_visit_with ( visitor)
78
104
}
79
105
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
+
80
112
/// Returns `true` if `self` has any late-bound regions that are either
81
113
/// bound by `binder` or bound by some binder outside of `binder`.
82
114
/// If `binder` is `ty::INNERMOST`, this indicates whether
@@ -168,24 +200,13 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
168
200
}
169
201
}
170
202
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.
185
206
///
186
207
/// 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 ,
189
210
/// a blanket implementation of [`FallibleTypeFolder`] will defer to
190
211
/// the infallible methods of this trait to ensure that the two APIs
191
212
/// are coherent.
@@ -238,11 +259,9 @@ pub trait TypeFolder<'tcx>: Sized {
238
259
}
239
260
}
240
261
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.
246
265
///
247
266
/// A blanket implementation of this trait (that defers to the relevant
248
267
/// method of [`TypeFolder`]) is provided for all infallible folders in
@@ -285,8 +304,8 @@ pub trait FallibleTypeFolder<'tcx>: TypeFolder<'tcx> {
285
304
}
286
305
}
287
306
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.
290
309
impl < ' tcx , F > FallibleTypeFolder < ' tcx > for F
291
310
where
292
311
F : TypeFolder < ' tcx , Error = !> ,
@@ -328,6 +347,9 @@ where
328
347
}
329
348
}
330
349
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.
331
353
pub trait TypeVisitor < ' tcx > : Sized {
332
354
type BreakTy = !;
333
355
0 commit comments