]>
Commit | Line | Data |
---|---|---|
9ffffee4 FG |
1 | //! A visiting traversal mechanism for complex data structures that contain type |
2 | //! information. | |
3 | //! | |
4 | //! This is a read-only traversal of the data structure. | |
5 | //! | |
6 | //! This traversal has limited flexibility. Only a small number of "types of | |
7 | //! interest" within the complex data structures can receive custom | |
8 | //! visitation. These are the ones containing the most important type-related | |
9 | //! information, such as `Ty`, `Predicate`, `Region`, and `Const`. | |
10 | //! | |
11 | //! There are three groups of traits involved in each traversal. | |
12 | //! - `TypeVisitable`. This is implemented once for many types, including: | |
13 | //! - Types of interest, for which the methods delegate to the visitor. | |
14 | //! - All other types, including generic containers like `Vec` and `Option`. | |
15 | //! It defines a "skeleton" of how they should be visited. | |
16 | //! - `TypeSuperVisitable`. This is implemented only for each type of interest, | |
17 | //! and defines the visiting "skeleton" for these types. | |
18 | //! - `TypeVisitor`. This is implemented for each visitor. This defines how | |
19 | //! types of interest are visited. | |
20 | //! | |
21 | //! This means each visit is a mixture of (a) generic visiting operations, and (b) | |
22 | //! custom visit operations that are specific to the visitor. | |
23 | //! - The `TypeVisitable` impls handle most of the traversal, and call into | |
24 | //! `TypeVisitor` when they encounter a type of interest. | |
25 | //! - A `TypeVisitor` may call into another `TypeVisitable` impl, because some of | |
26 | //! the types of interest are recursive and can contain other types of interest. | |
27 | //! - A `TypeVisitor` may also call into a `TypeSuperVisitable` impl, because each | |
28 | //! visitor might provide custom handling only for some types of interest, or | |
29 | //! only for some variants of each type of interest, and then use default | |
30 | //! traversal for the remaining cases. | |
31 | //! | |
32 | //! For example, if you have `struct S(Ty, U)` where `S: TypeVisitable` and `U: | |
33 | //! TypeVisitable`, and an instance `s = S(ty, u)`, it would be visited like so: | |
34 | //! ```text | |
35 | //! s.visit_with(visitor) calls | |
36 | //! - ty.visit_with(visitor) calls | |
37 | //! - visitor.visit_ty(ty) may call | |
38 | //! - ty.super_visit_with(visitor) | |
39 | //! - u.visit_with(visitor) | |
40 | //! ``` | |
41 | use crate::Interner; | |
42 | ||
43 | use std::fmt; | |
44 | use std::ops::ControlFlow; | |
45 | ||
46 | /// This trait is implemented for every type that can be visited, | |
47 | /// providing the skeleton of the traversal. | |
48 | /// | |
49 | /// To implement this conveniently, use the derive macro located in | |
50 | /// `rustc_macros`. | |
51 | pub trait TypeVisitable<I: Interner>: fmt::Debug + Clone { | |
52 | /// The entry point for visiting. To visit a value `t` with a visitor `v` | |
53 | /// call: `t.visit_with(v)`. | |
54 | /// | |
55 | /// For most types, this just traverses the value, calling `visit_with` on | |
56 | /// each field/element. | |
57 | /// | |
58 | /// For types of interest (such as `Ty`), the implementation of this method | |
59 | /// that calls a visitor method specifically for that type (such as | |
60 | /// `V::visit_ty`). This is where control transfers from `TypeFoldable` to | |
61 | /// `TypeVisitor`. | |
62 | fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>; | |
63 | } | |
64 | ||
65 | pub trait TypeSuperVisitable<I: Interner>: TypeVisitable<I> { | |
66 | /// Provides a default visit for a type of interest. This should only be | |
67 | /// called within `TypeVisitor` methods, when a non-custom traversal is | |
68 | /// desired for the value of the type of interest passed to that method. | |
69 | /// For example, in `MyVisitor::visit_ty(ty)`, it is valid to call | |
70 | /// `ty.super_visit_with(self)`, but any other visiting should be done | |
71 | /// with `xyz.visit_with(self)`. | |
72 | fn super_visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>; | |
73 | } | |
74 | ||
75 | /// This trait is implemented for every visiting traversal. There is a visit | |
76 | /// method defined for every type of interest. Each such method has a default | |
77 | /// that recurses into the type's fields in a non-custom fashion. | |
78 | pub trait TypeVisitor<I: Interner>: Sized { | |
79 | type BreakTy = !; | |
80 | ||
81 | fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &I::Binder<T>) -> ControlFlow<Self::BreakTy> | |
82 | where | |
83 | I::Binder<T>: TypeSuperVisitable<I>, | |
84 | { | |
85 | t.super_visit_with(self) | |
86 | } | |
87 | ||
88 | fn visit_ty(&mut self, t: I::Ty) -> ControlFlow<Self::BreakTy> | |
89 | where | |
90 | I::Ty: TypeSuperVisitable<I>, | |
91 | { | |
92 | t.super_visit_with(self) | |
93 | } | |
94 | ||
95 | fn visit_region(&mut self, r: I::Region) -> ControlFlow<Self::BreakTy> | |
96 | where | |
97 | I::Region: TypeSuperVisitable<I>, | |
98 | { | |
99 | r.super_visit_with(self) | |
100 | } | |
101 | ||
102 | fn visit_const(&mut self, c: I::Const) -> ControlFlow<Self::BreakTy> | |
103 | where | |
104 | I::Const: TypeSuperVisitable<I>, | |
105 | { | |
106 | c.super_visit_with(self) | |
107 | } | |
108 | ||
109 | fn visit_predicate(&mut self, p: I::Predicate) -> ControlFlow<Self::BreakTy> | |
110 | where | |
111 | I::Predicate: TypeSuperVisitable<I>, | |
112 | { | |
113 | p.super_visit_with(self) | |
114 | } | |
115 | } |