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        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
246/// Invokes `callback` on each immediate subpattern of `pat`, if any.
247/// A building block for assembling THIR pattern visitors.
248pub(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}