|
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