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