rustc_middle/thir/
visit.rs

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