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