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