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