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