1use super::{
2 AdtExpr, AdtExprBase, Arm, Block, ClosureExpr, Expr, ExprKind, InlineAsmExpr, InlineAsmOperand,
3 Pat, PatKind, Stmt, StmtKind, Thir,
4};
5
6pub trait Visitor<'thir, 'tcx: 'thir>: Sized {
7 fn thir(&self) -> &'thir Thir<'tcx>;
8
9 fn visit_expr(&mut self, expr: &'thir Expr<'tcx>) {
10 walk_expr(self, expr);
11 }
12
13 fn visit_stmt(&mut self, stmt: &'thir Stmt<'tcx>) {
14 walk_stmt(self, stmt);
15 }
16
17 fn visit_block(&mut self, block: &'thir Block) {
18 walk_block(self, block);
19 }
20
21 fn visit_arm(&mut self, arm: &'thir Arm<'tcx>) {
22 walk_arm(self, arm);
23 }
24
25 fn visit_pat(&mut self, pat: &'thir Pat<'tcx>) {
26 walk_pat(self, pat);
27 }
28
29 }
38
39pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
40 visitor: &mut V,
41 expr: &'thir Expr<'tcx>,
42) {
43 use ExprKind::*;
44 match expr.kind {
45 Scope { value, region_scope: _, lint_level: _ } => {
46 visitor.visit_expr(&visitor.thir()[value])
47 }
48 Box { value } => visitor.visit_expr(&visitor.thir()[value]),
49 If { cond, then, else_opt, if_then_scope: _ } => {
50 visitor.visit_expr(&visitor.thir()[cond]);
51 visitor.visit_expr(&visitor.thir()[then]);
52 if let Some(else_expr) = else_opt {
53 visitor.visit_expr(&visitor.thir()[else_expr]);
54 }
55 }
56 Call { fun, ref args, ty: _, from_hir_call: _, fn_span: _ } => {
57 visitor.visit_expr(&visitor.thir()[fun]);
58 for &arg in &**args {
59 visitor.visit_expr(&visitor.thir()[arg]);
60 }
61 }
62 Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]),
63 Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => {
64 visitor.visit_expr(&visitor.thir()[lhs]);
65 visitor.visit_expr(&visitor.thir()[rhs]);
66 }
67 Unary { arg, op: _ } => visitor.visit_expr(&visitor.thir()[arg]),
68 Cast { source } => visitor.visit_expr(&visitor.thir()[source]),
69 Use { source } => visitor.visit_expr(&visitor.thir()[source]),
70 NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]),
71 PointerCoercion { source, cast: _, is_from_as_cast: _ } => {
72 visitor.visit_expr(&visitor.thir()[source])
73 }
74 Let { expr, ref pat } => {
75 visitor.visit_expr(&visitor.thir()[expr]);
76 visitor.visit_pat(pat);
77 }
78 Loop { body } => visitor.visit_expr(&visitor.thir()[body]),
79 Match { scrutinee, ref arms, .. } => {
80 visitor.visit_expr(&visitor.thir()[scrutinee]);
81 for &arm in &**arms {
82 visitor.visit_arm(&visitor.thir()[arm]);
83 }
84 }
85 Block { block } => visitor.visit_block(&visitor.thir()[block]),
86 Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => {
87 visitor.visit_expr(&visitor.thir()[lhs]);
88 visitor.visit_expr(&visitor.thir()[rhs]);
89 }
90 Field { lhs, variant_index: _, name: _ } => visitor.visit_expr(&visitor.thir()[lhs]),
91 Index { lhs, index } => {
92 visitor.visit_expr(&visitor.thir()[lhs]);
93 visitor.visit_expr(&visitor.thir()[index]);
94 }
95 VarRef { id: _ } | UpvarRef { closure_def_id: _, var_hir_id: _ } => {}
96 Borrow { arg, borrow_kind: _ } => visitor.visit_expr(&visitor.thir()[arg]),
97 RawBorrow { arg, mutability: _ } => visitor.visit_expr(&visitor.thir()[arg]),
98 Break { value, label: _ } => {
99 if let Some(value) = value {
100 visitor.visit_expr(&visitor.thir()[value])
101 }
102 }
103 Continue { label: _ } => {}
104 Return { value } => {
105 if let Some(value) = value {
106 visitor.visit_expr(&visitor.thir()[value])
107 }
108 }
109 Become { value } => visitor.visit_expr(&visitor.thir()[value]),
110 ConstBlock { did: _, args: _ } => {}
111 Repeat { value, count: _ } => {
112 visitor.visit_expr(&visitor.thir()[value]);
113 }
114 Array { ref fields } | Tuple { ref fields } => {
115 for &field in &**fields {
116 visitor.visit_expr(&visitor.thir()[field]);
117 }
118 }
119 Adt(box AdtExpr {
120 ref fields,
121 ref base,
122 adt_def: _,
123 variant_index: _,
124 args: _,
125 user_ty: _,
126 }) => {
127 for field in &**fields {
128 visitor.visit_expr(&visitor.thir()[field.expr]);
129 }
130 if let AdtExprBase::Base(base) = base {
131 visitor.visit_expr(&visitor.thir()[base.base]);
132 }
133 }
134 PlaceTypeAscription { source, user_ty: _, user_ty_span: _ }
135 | ValueTypeAscription { source, user_ty: _, user_ty_span: _ } => {
136 visitor.visit_expr(&visitor.thir()[source])
137 }
138 PlaceUnwrapUnsafeBinder { source }
139 | ValueUnwrapUnsafeBinder { source }
140 | WrapUnsafeBinder { source } => visitor.visit_expr(&visitor.thir()[source]),
141 Closure(box ClosureExpr {
142 closure_id: _,
143 args: _,
144 upvars: _,
145 movability: _,
146 fake_reads: _,
147 }) => {}
148 Literal { lit: _, neg: _ } => {}
149 NonHirLiteral { lit: _, user_ty: _ } => {}
150 ZstLiteral { user_ty: _ } => {}
151 NamedConst { def_id: _, args: _, user_ty: _ } => {}
152 ConstParam { param: _, def_id: _ } => {}
153 StaticRef { alloc_id: _, ty: _, def_id: _ } => {}
154 InlineAsm(box InlineAsmExpr {
155 asm_macro: _,
156 ref operands,
157 template: _,
158 options: _,
159 line_spans: _,
160 }) => {
161 for op in &**operands {
162 use InlineAsmOperand::*;
163 match op {
164 In { expr, reg: _ }
165 | Out { expr: Some(expr), reg: _, late: _ }
166 | InOut { expr, reg: _, late: _ } => visitor.visit_expr(&visitor.thir()[*expr]),
167 SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
168 visitor.visit_expr(&visitor.thir()[*in_expr]);
169 if let Some(out_expr) = out_expr {
170 visitor.visit_expr(&visitor.thir()[*out_expr]);
171 }
172 }
173 Out { expr: None, reg: _, late: _ }
174 | Const { value: _, span: _ }
175 | SymFn { value: _, span: _ }
176 | SymStatic { def_id: _ } => {}
177 Label { block } => visitor.visit_block(&visitor.thir()[*block]),
178 }
179 }
180 }
181 OffsetOf { container: _, fields: _ } => {}
182 ThreadLocalRef(_) => {}
183 Yield { value } => visitor.visit_expr(&visitor.thir()[value]),
184 }
185}
186
187pub fn walk_stmt<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
188 visitor: &mut V,
189 stmt: &'thir Stmt<'tcx>,
190) {
191 match &stmt.kind {
192 StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[*expr]),
193 StmtKind::Let {
194 initializer,
195 remainder_scope: _,
196 init_scope: _,
197 ref pattern,
198 lint_level: _,
199 else_block,
200 span: _,
201 } => {
202 if let Some(init) = initializer {
203 visitor.visit_expr(&visitor.thir()[*init]);
204 }
205 visitor.visit_pat(pattern);
206 if let Some(block) = else_block {
207 visitor.visit_block(&visitor.thir()[*block])
208 }
209 }
210 }
211}
212
213pub fn walk_block<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
214 visitor: &mut V,
215 block: &'thir Block,
216) {
217 for &stmt in &*block.stmts {
218 visitor.visit_stmt(&visitor.thir()[stmt]);
219 }
220 if let Some(expr) = block.expr {
221 visitor.visit_expr(&visitor.thir()[expr]);
222 }
223}
224
225pub fn walk_arm<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
226 visitor: &mut V,
227 arm: &'thir Arm<'tcx>,
228) {
229 if let Some(expr) = arm.guard {
230 visitor.visit_expr(&visitor.thir()[expr])
231 }
232 visitor.visit_pat(&arm.pattern);
233 visitor.visit_expr(&visitor.thir()[arm.body]);
234}
235
236pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
237 visitor: &mut V,
238 pat: &'thir Pat<'tcx>,
239) {
240 use PatKind::*;
241 match &pat.kind {
242 AscribeUserType { subpattern, ascription: _ }
243 | Deref { subpattern }
244 | DerefPattern { subpattern, .. }
245 | Binding { subpattern: Some(subpattern), .. } => visitor.visit_pat(subpattern),
246 Binding { .. } | Wild | Never | Error(_) => {}
247 Variant { subpatterns, adt_def: _, args: _, variant_index: _ } | Leaf { subpatterns } => {
248 for subpattern in subpatterns {
249 visitor.visit_pat(&subpattern.pattern);
250 }
251 }
252 Constant { value: _ } => {}
253 ExpandedConstant { def_id: _, is_inline: _, subpattern } => visitor.visit_pat(subpattern),
254 Range(_) => {}
255 Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => {
256 for subpattern in prefix.iter() {
257 visitor.visit_pat(subpattern);
258 }
259 if let Some(pat) = slice {
260 visitor.visit_pat(pat);
261 }
262 for subpattern in suffix.iter() {
263 visitor.visit_pat(subpattern);
264 }
265 }
266 Or { pats } => {
267 for pat in pats.iter() {
268 visitor.visit_pat(pat);
269 }
270 }
271 };
272}