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