|
1 |
| -//! A folding traversal mechanism for complex data structures that contain type |
2 |
| -//! information. |
3 |
| -//! |
4 |
| -//! This is a modifying traversal. It consumes the data structure, producing a |
5 |
| -//! (possibly) modified version of it. Both fallible and infallible versions are |
6 |
| -//! available. The name is potentially confusing, because this traversal is more |
7 |
| -//! like `Iterator::map` than `Iterator::fold`. |
8 |
| -//! |
9 |
| -//! This traversal has limited flexibility. Only a small number of "types of |
10 |
| -//! interest" within the complex data structures can receive custom |
11 |
| -//! modification. These are the ones containing the most important type-related |
12 |
| -//! information, such as `Ty`, `Predicate`, `Region`, and `Const`. |
13 |
| -//! |
14 |
| -//! There are three groups of traits involved in each traversal. |
15 |
| -//! - `TypeFoldable`. This is implemented once for many types, including: |
16 |
| -//! - Types of interest, for which the methods delegate to the folder. |
17 |
| -//! - All other types, including generic containers like `Vec` and `Option`. |
18 |
| -//! It defines a "skeleton" of how they should be folded. |
19 |
| -//! - `TypeSuperFoldable`. This is implemented only for each type of interest, |
20 |
| -//! and defines the folding "skeleton" for these types. |
21 |
| -//! - `TypeFolder`/`FallibleTypeFolder. One of these is implemented for each |
22 |
| -//! folder. This defines how types of interest are folded. |
23 |
| -//! |
24 |
| -//! This means each fold is a mixture of (a) generic folding operations, and (b) |
25 |
| -//! custom fold operations that are specific to the folder. |
26 |
| -//! - The `TypeFoldable` impls handle most of the traversal, and call into |
27 |
| -//! `TypeFolder`/`FallibleTypeFolder` when they encounter a type of interest. |
28 |
| -//! - A `TypeFolder`/`FallibleTypeFolder` may call into another `TypeFoldable` |
29 |
| -//! impl, because some of the types of interest are recursive and can contain |
30 |
| -//! other types of interest. |
31 |
| -//! - A `TypeFolder`/`FallibleTypeFolder` may also call into a `TypeSuperFoldable` |
32 |
| -//! impl, because each folder might provide custom handling only for some types |
33 |
| -//! of interest, or only for some variants of each type of interest, and then |
34 |
| -//! use default traversal for the remaining cases. |
35 |
| -//! |
36 |
| -//! For example, if you have `struct S(Ty, U)` where `S: TypeFoldable` and `U: |
37 |
| -//! TypeFoldable`, and an instance `s = S(ty, u)`, it would be folded like so: |
38 |
| -//! ```text |
39 |
| -//! s.fold_with(folder) calls |
40 |
| -//! - ty.fold_with(folder) calls |
41 |
| -//! - folder.fold_ty(ty) may call |
42 |
| -//! - ty.super_fold_with(folder) |
43 |
| -//! - u.fold_with(folder) |
44 |
| -//! ``` |
45 |
| -use crate::ty::{self, Binder, BoundTy, Interner, Ty, TyCtxt, TypeVisitable}; |
| 1 | +use crate::ty::{self, Binder, BoundTy, Ty, TyCtxt, TypeVisitable}; |
46 | 2 | use rustc_data_structures::fx::FxIndexMap;
|
47 | 3 | use rustc_hir::def_id::DefId;
|
48 | 4 |
|
49 | 5 | use std::collections::BTreeMap;
|
50 | 6 |
|
51 |
| -/// This trait is implemented for every type that can be folded, |
52 |
| -/// providing the skeleton of the traversal. |
53 |
| -/// |
54 |
| -/// To implement this conveniently, use the derive macro located in |
55 |
| -/// `rustc_macros`. |
56 |
| -pub trait TypeFoldable<I: Interner>: TypeVisitable<I> { |
57 |
| - /// The entry point for folding. To fold a value `t` with a folder `f` |
58 |
| - /// call: `t.try_fold_with(f)`. |
59 |
| - /// |
60 |
| - /// For most types, this just traverses the value, calling `try_fold_with` |
61 |
| - /// on each field/element. |
62 |
| - /// |
63 |
| - /// For types of interest (such as `Ty`), the implementation of method |
64 |
| - /// calls a folder method specifically for that type (such as |
65 |
| - /// `F::try_fold_ty`). This is where control transfers from `TypeFoldable` |
66 |
| - /// to `TypeFolder`. |
67 |
| - fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error>; |
68 |
| - |
69 |
| - /// A convenient alternative to `try_fold_with` for use with infallible |
70 |
| - /// folders. Do not override this method, to ensure coherence with |
71 |
| - /// `try_fold_with`. |
72 |
| - fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self { |
73 |
| - self.try_fold_with(folder).into_ok() |
74 |
| - } |
75 |
| -} |
76 |
| - |
77 |
| -// This trait is implemented for types of interest. |
78 |
| -pub trait TypeSuperFoldable<I: Interner>: TypeFoldable<I> { |
79 |
| - /// Provides a default fold for a type of interest. This should only be |
80 |
| - /// called within `TypeFolder` methods, when a non-custom traversal is |
81 |
| - /// desired for the value of the type of interest passed to that method. |
82 |
| - /// For example, in `MyFolder::try_fold_ty(ty)`, it is valid to call |
83 |
| - /// `ty.try_super_fold_with(self)`, but any other folding should be done |
84 |
| - /// with `xyz.try_fold_with(self)`. |
85 |
| - fn try_super_fold_with<F: FallibleTypeFolder<I>>( |
86 |
| - self, |
87 |
| - folder: &mut F, |
88 |
| - ) -> Result<Self, F::Error>; |
89 |
| - |
90 |
| - /// A convenient alternative to `try_super_fold_with` for use with |
91 |
| - /// infallible folders. Do not override this method, to ensure coherence |
92 |
| - /// with `try_super_fold_with`. |
93 |
| - fn super_fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self { |
94 |
| - self.try_super_fold_with(folder).into_ok() |
95 |
| - } |
96 |
| -} |
97 |
| - |
98 |
| -/// This trait is implemented for every infallible folding traversal. There is |
99 |
| -/// a fold method defined for every type of interest. Each such method has a |
100 |
| -/// default that does an "identity" fold. Implementations of these methods |
101 |
| -/// often fall back to a `super_fold_with` method if the primary argument |
102 |
| -/// doesn't satisfy a particular condition. |
103 |
| -/// |
104 |
| -/// A blanket implementation of [`FallibleTypeFolder`] will defer to |
105 |
| -/// the infallible methods of this trait to ensure that the two APIs |
106 |
| -/// are coherent. |
107 |
| -pub trait TypeFolder<I: Interner>: FallibleTypeFolder<I, Error = !> { |
108 |
| - fn tcx(&self) -> I; |
109 |
| - |
110 |
| - fn fold_binder<T>(&mut self, t: I::Binder<T>) -> I::Binder<T> |
111 |
| - where |
112 |
| - T: TypeFoldable<I>, |
113 |
| - I::Binder<T>: TypeSuperFoldable<I>, |
114 |
| - { |
115 |
| - t.super_fold_with(self) |
116 |
| - } |
117 |
| - |
118 |
| - fn fold_ty(&mut self, t: I::Ty) -> I::Ty |
119 |
| - where |
120 |
| - I::Ty: TypeSuperFoldable<I>, |
121 |
| - { |
122 |
| - t.super_fold_with(self) |
123 |
| - } |
124 |
| - |
125 |
| - fn fold_region(&mut self, r: I::Region) -> I::Region |
126 |
| - where |
127 |
| - I::Region: TypeSuperFoldable<I>, |
128 |
| - { |
129 |
| - r.super_fold_with(self) |
130 |
| - } |
131 |
| - |
132 |
| - fn fold_const(&mut self, c: I::Const) -> I::Const |
133 |
| - where |
134 |
| - I::Const: TypeSuperFoldable<I>, |
135 |
| - { |
136 |
| - c.super_fold_with(self) |
137 |
| - } |
138 |
| - |
139 |
| - fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate |
140 |
| - where |
141 |
| - I::Predicate: TypeSuperFoldable<I>, |
142 |
| - { |
143 |
| - p.super_fold_with(self) |
144 |
| - } |
145 |
| -} |
146 |
| - |
147 |
| -/// This trait is implemented for every folding traversal. There is a fold |
148 |
| -/// method defined for every type of interest. Each such method has a default |
149 |
| -/// that does an "identity" fold. |
150 |
| -/// |
151 |
| -/// A blanket implementation of this trait (that defers to the relevant |
152 |
| -/// method of [`TypeFolder`]) is provided for all infallible folders in |
153 |
| -/// order to ensure the two APIs are coherent. |
154 |
| -pub trait FallibleTypeFolder<I: Interner>: Sized { |
155 |
| - type Error; |
156 |
| - |
157 |
| - fn tcx(&self) -> I; |
158 |
| - |
159 |
| - fn try_fold_binder<T>(&mut self, t: I::Binder<T>) -> Result<I::Binder<T>, Self::Error> |
160 |
| - where |
161 |
| - T: TypeFoldable<I>, |
162 |
| - I::Binder<T>: TypeSuperFoldable<I>, |
163 |
| - { |
164 |
| - t.try_super_fold_with(self) |
165 |
| - } |
166 |
| - |
167 |
| - fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, Self::Error> |
168 |
| - where |
169 |
| - I::Ty: TypeSuperFoldable<I>, |
170 |
| - { |
171 |
| - t.try_super_fold_with(self) |
172 |
| - } |
173 |
| - |
174 |
| - fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, Self::Error> |
175 |
| - where |
176 |
| - I::Region: TypeSuperFoldable<I>, |
177 |
| - { |
178 |
| - r.try_super_fold_with(self) |
179 |
| - } |
180 |
| - |
181 |
| - fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, Self::Error> |
182 |
| - where |
183 |
| - I::Const: TypeSuperFoldable<I>, |
184 |
| - { |
185 |
| - c.try_super_fold_with(self) |
186 |
| - } |
187 |
| - |
188 |
| - fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Self::Error> |
189 |
| - where |
190 |
| - I::Predicate: TypeSuperFoldable<I>, |
191 |
| - { |
192 |
| - p.try_super_fold_with(self) |
193 |
| - } |
194 |
| -} |
195 |
| - |
196 |
| -// This blanket implementation of the fallible trait for infallible folders |
197 |
| -// delegates to infallible methods to ensure coherence. |
198 |
| -impl<I: Interner, F> FallibleTypeFolder<I> for F |
199 |
| -where |
200 |
| - F: TypeFolder<I>, |
201 |
| -{ |
202 |
| - type Error = !; |
203 |
| - |
204 |
| - fn tcx(&self) -> I { |
205 |
| - TypeFolder::tcx(self) |
206 |
| - } |
207 |
| - |
208 |
| - fn try_fold_binder<T>(&mut self, t: I::Binder<T>) -> Result<I::Binder<T>, !> |
209 |
| - where |
210 |
| - T: TypeFoldable<I>, |
211 |
| - I::Binder<T>: TypeSuperFoldable<I>, |
212 |
| - { |
213 |
| - Ok(self.fold_binder(t)) |
214 |
| - } |
215 |
| - |
216 |
| - fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, !> |
217 |
| - where |
218 |
| - I::Ty: TypeSuperFoldable<I>, |
219 |
| - { |
220 |
| - Ok(self.fold_ty(t)) |
221 |
| - } |
222 |
| - |
223 |
| - fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, !> |
224 |
| - where |
225 |
| - I::Region: TypeSuperFoldable<I>, |
226 |
| - { |
227 |
| - Ok(self.fold_region(r)) |
228 |
| - } |
229 |
| - |
230 |
| - fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, !> |
231 |
| - where |
232 |
| - I::Const: TypeSuperFoldable<I>, |
233 |
| - { |
234 |
| - Ok(self.fold_const(c)) |
235 |
| - } |
236 |
| - |
237 |
| - fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, !> |
238 |
| - where |
239 |
| - I::Predicate: TypeSuperFoldable<I>, |
240 |
| - { |
241 |
| - Ok(self.fold_predicate(p)) |
242 |
| - } |
243 |
| -} |
| 7 | +pub use rustc_type_ir::fold::*; |
244 | 8 |
|
245 | 9 | ///////////////////////////////////////////////////////////////////////////
|
246 | 10 | // Some sample folders
|
|
0 commit comments