]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_type_ir/src/visit.rs
New upstream version 1.69.0+dfsg1
[rustc.git] / compiler / rustc_type_ir / src / visit.rs
CommitLineData
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//! ```
41use crate::Interner;
42
43use std::fmt;
44use 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`.
51pub 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
65pub 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.
78pub 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}