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