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
6/// Every `walk_*` method uses deconstruction to access fields of structs and
7/// enums. This will result in a compile error if a field is added, which makes
8/// it more likely the appropriate visit call will be added for it.
9pub trait Visitor<'thir, 'tcx: 'thir>: Sized {
10    fn thir(&self) -> &'thir Thir<'tcx>;
11
12    fn visit_expr(&mut self, expr: &'thir Expr<'tcx>) {
13        walk_expr(self, expr);
14    }
15
16    fn visit_stmt(&mut self, stmt: &'thir Stmt<'tcx>) {
17        walk_stmt(self, stmt);
18    }
19
20    fn visit_block(&mut self, block: &'thir Block) {
21        walk_block(self, block);
22    }
23
24    fn visit_arm(&mut self, arm: &'thir Arm<'tcx>) {
25        walk_arm(self, arm);
26    }
27
28    fn visit_pat(&mut self, pat: &'thir Pat<'tcx>) {
29        walk_pat(self, pat);
30    }
31
32    // Note: We don't have visitors for `ty::Const` and `mir::Const`
33    // (even though these types occur in THIR) for consistency and to reduce confusion,
34    // since the lazy creation of constants during thir construction causes most
35    // 'constants' to not be of type `ty::Const` or `mir::Const` at that
36    // stage (they are mostly still identified by `DefId` or `hir::Lit`, see
37    // the variants `Literal`, `NonHirLiteral` and `NamedConst` in `thir::ExprKind`).
38    // You have to manually visit `ty::Const` and `mir::Const` through the
39    // other `visit*` functions.
40}
41
42pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
43    visitor: &mut V,
44    expr: &'thir Expr<'tcx>,
45) {
46    use ExprKind::*;
47    let Expr { kind, ty: _, temp_lifetime: _, span: _ } = expr;
48    match *kind {
49        Scope { value, region_scope: _, lint_level: _ } => {
50            visitor.visit_expr(&visitor.thir()[value])
51        }
52        Box { value } => visitor.visit_expr(&visitor.thir()[value]),
53        If { cond, then, else_opt, if_then_scope: _ } => {
54            visitor.visit_expr(&visitor.thir()[cond]);
55            visitor.visit_expr(&visitor.thir()[then]);
56            if let Some(else_expr) = else_opt {
57                visitor.visit_expr(&visitor.thir()[else_expr]);
58            }
59        }
60        Call { fun, ref args, ty: _, from_hir_call: _, fn_span: _ } => {
61            visitor.visit_expr(&visitor.thir()[fun]);
62            for &arg in &**args {
63                visitor.visit_expr(&visitor.thir()[arg]);
64            }
65        }
66        ByUse { expr, span: _ } => {
67            visitor.visit_expr(&visitor.thir()[expr]);
68        }
69        Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]),
70        Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => {
71            visitor.visit_expr(&visitor.thir()[lhs]);
72            visitor.visit_expr(&visitor.thir()[rhs]);
73        }
74        Unary { arg, op: _ } => visitor.visit_expr(&visitor.thir()[arg]),
75        Cast { source } => visitor.visit_expr(&visitor.thir()[source]),
76        Use { source } => visitor.visit_expr(&visitor.thir()[source]),
77        NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]),
78        PointerCoercion { source, cast: _, is_from_as_cast: _ } => {
79            visitor.visit_expr(&visitor.thir()[source])
80        }
81        Let { expr, ref pat } => {
82            visitor.visit_expr(&visitor.thir()[expr]);
83            visitor.visit_pat(pat);
84        }
85        Loop { body } => visitor.visit_expr(&visitor.thir()[body]),
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        Return { value } => {
112            if let Some(value) = value {
113                visitor.visit_expr(&visitor.thir()[value])
114            }
115        }
116        Become { value } => visitor.visit_expr(&visitor.thir()[value]),
117        ConstBlock { did: _, args: _ } => {}
118        Repeat { value, count: _ } => {
119            visitor.visit_expr(&visitor.thir()[value]);
120        }
121        Array { ref fields } | Tuple { ref fields } => {
122            for &field in &**fields {
123                visitor.visit_expr(&visitor.thir()[field]);
124            }
125        }
126        Adt(box AdtExpr {
127            ref fields,
128            ref base,
129            adt_def: _,
130            variant_index: _,
131            args: _,
132            user_ty: _,
133        }) => {
134            for field in &**fields {
135                visitor.visit_expr(&visitor.thir()[field.expr]);
136            }
137            if let AdtExprBase::Base(base) = base {
138                visitor.visit_expr(&visitor.thir()[base.base]);
139            }
140        }
141        PlaceTypeAscription { source, user_ty: _, user_ty_span: _ }
142        | ValueTypeAscription { source, user_ty: _, user_ty_span: _ } => {
143            visitor.visit_expr(&visitor.thir()[source])
144        }
145        PlaceUnwrapUnsafeBinder { source }
146        | ValueUnwrapUnsafeBinder { source }
147        | WrapUnsafeBinder { source } => visitor.visit_expr(&visitor.thir()[source]),
148        Closure(box ClosureExpr {
149            closure_id: _,
150            args: _,
151            upvars: _,
152            movability: _,
153            fake_reads: _,
154        }) => {}
155        Literal { lit: _, neg: _ } => {}
156        NonHirLiteral { lit: _, user_ty: _ } => {}
157        ZstLiteral { user_ty: _ } => {}
158        NamedConst { def_id: _, args: _, user_ty: _ } => {}
159        ConstParam { param: _, def_id: _ } => {}
160        StaticRef { alloc_id: _, ty: _, def_id: _ } => {}
161        InlineAsm(box InlineAsmExpr {
162            asm_macro: _,
163            ref operands,
164            template: _,
165            options: _,
166            line_spans: _,
167        }) => {
168            for op in &**operands {
169                use InlineAsmOperand::*;
170                match op {
171                    In { expr, reg: _ }
172                    | Out { expr: Some(expr), reg: _, late: _ }
173                    | InOut { expr, reg: _, late: _ } => visitor.visit_expr(&visitor.thir()[*expr]),
174                    SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
175                        visitor.visit_expr(&visitor.thir()[*in_expr]);
176                        if let Some(out_expr) = out_expr {
177                            visitor.visit_expr(&visitor.thir()[*out_expr]);
178                        }
179                    }
180                    Out { expr: None, reg: _, late: _ }
181                    | Const { value: _, span: _ }
182                    | SymFn { value: _ }
183                    | SymStatic { def_id: _ } => {}
184                    Label { block } => visitor.visit_block(&visitor.thir()[*block]),
185                }
186            }
187        }
188        OffsetOf { container: _, fields: _ } => {}
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            lint_level: _,
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, lint_level: _, 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
254/// Invokes `callback` on each immediate subpattern of `pat`, if any.
255/// A building block for assembling THIR pattern visitors.
256pub(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: _ } = 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::AscribeUserType { subpattern, .. }
271        | PatKind::Binding { subpattern: Some(subpattern), .. }
272        | PatKind::Deref { subpattern }
273        | PatKind::DerefPattern { subpattern, .. }
274        | PatKind::ExpandedConstant { subpattern, .. } => callback(subpattern),
275
276        PatKind::Variant { subpatterns, .. } | PatKind::Leaf { subpatterns } => {
277            for field_pat in subpatterns {
278                callback(&field_pat.pattern);
279            }
280        }
281
282        PatKind::Slice { prefix, slice, suffix } | PatKind::Array { prefix, slice, suffix } => {
283            for pat in prefix.iter().chain(slice.as_deref()).chain(suffix) {
284                callback(pat);
285            }
286        }
287
288        PatKind::Or { pats } => {
289            for pat in pats {
290                callback(pat);
291            }
292        }
293    }
294}