]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_middle/src/thir/visit.rs
Merge commit 'a8385522ade6f67853edac730b5bf164ddb298fd' into simd-remove-autosplats
[rust.git] / compiler / rustc_middle / src / thir / visit.rs
1 use super::{
2     Arm, Block, Expr, ExprKind, Guard, InlineAsmOperand, Pat, PatKind, Stmt, StmtKind, Thir,
3 };
4 use rustc_middle::ty::Const;
5
6 pub trait Visitor<'a, 'tcx: 'a>: Sized {
7     fn thir(&self) -> &'a Thir<'tcx>;
8
9     fn visit_expr(&mut self, expr: &Expr<'tcx>) {
10         walk_expr(self, expr);
11     }
12
13     fn visit_stmt(&mut self, stmt: &Stmt<'tcx>) {
14         walk_stmt(self, stmt);
15     }
16
17     fn visit_block(&mut self, block: &Block) {
18         walk_block(self, block);
19     }
20
21     fn visit_arm(&mut self, arm: &Arm<'tcx>) {
22         walk_arm(self, arm);
23     }
24
25     fn visit_pat(&mut self, pat: &Pat<'tcx>) {
26         walk_pat(self, pat);
27     }
28
29     fn visit_const(&mut self, _cnst: &'tcx Const<'tcx>) {}
30 }
31
32 pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) {
33     use ExprKind::*;
34     match expr.kind {
35         Scope { value, region_scope: _, lint_level: _ } => {
36             visitor.visit_expr(&visitor.thir()[value])
37         }
38         Box { value } => visitor.visit_expr(&visitor.thir()[value]),
39         If { cond, then, else_opt, if_then_scope: _ } => {
40             visitor.visit_expr(&visitor.thir()[cond]);
41             visitor.visit_expr(&visitor.thir()[then]);
42             if let Some(else_expr) = else_opt {
43                 visitor.visit_expr(&visitor.thir()[else_expr]);
44             }
45         }
46         Call { fun, ref args, ty: _, from_hir_call: _, fn_span: _ } => {
47             visitor.visit_expr(&visitor.thir()[fun]);
48             for &arg in &**args {
49                 visitor.visit_expr(&visitor.thir()[arg]);
50             }
51         }
52         Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]),
53         Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => {
54             visitor.visit_expr(&visitor.thir()[lhs]);
55             visitor.visit_expr(&visitor.thir()[rhs]);
56         }
57         Unary { arg, op: _ } => visitor.visit_expr(&visitor.thir()[arg]),
58         Cast { source } => visitor.visit_expr(&visitor.thir()[source]),
59         Use { source } => visitor.visit_expr(&visitor.thir()[source]),
60         NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]),
61         Pointer { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]),
62         Let { expr, .. } => {
63             visitor.visit_expr(&visitor.thir()[expr]);
64         }
65         Loop { body } => visitor.visit_expr(&visitor.thir()[body]),
66         Match { scrutinee, ref arms } => {
67             visitor.visit_expr(&visitor.thir()[scrutinee]);
68             for &arm in &**arms {
69                 visitor.visit_arm(&visitor.thir()[arm]);
70             }
71         }
72         Block { ref body } => visitor.visit_block(body),
73         Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => {
74             visitor.visit_expr(&visitor.thir()[lhs]);
75             visitor.visit_expr(&visitor.thir()[rhs]);
76         }
77         Field { lhs, name: _ } => visitor.visit_expr(&visitor.thir()[lhs]),
78         Index { lhs, index } => {
79             visitor.visit_expr(&visitor.thir()[lhs]);
80             visitor.visit_expr(&visitor.thir()[index]);
81         }
82         VarRef { id: _ } | UpvarRef { closure_def_id: _, var_hir_id: _ } => {}
83         Borrow { arg, borrow_kind: _ } => visitor.visit_expr(&visitor.thir()[arg]),
84         AddressOf { arg, mutability: _ } => visitor.visit_expr(&visitor.thir()[arg]),
85         Break { value, label: _ } => {
86             if let Some(value) = value {
87                 visitor.visit_expr(&visitor.thir()[value])
88             }
89         }
90         Continue { label: _ } => {}
91         Return { value } => {
92             if let Some(value) = value {
93                 visitor.visit_expr(&visitor.thir()[value])
94             }
95         }
96         ConstBlock { value } => visitor.visit_const(value),
97         Repeat { value, count } => {
98             visitor.visit_expr(&visitor.thir()[value]);
99             visitor.visit_const(count);
100         }
101         Array { ref fields } | Tuple { ref fields } => {
102             for &field in &**fields {
103                 visitor.visit_expr(&visitor.thir()[field]);
104             }
105         }
106         Adt(box crate::thir::Adt {
107             ref fields,
108             ref base,
109             adt_def: _,
110             variant_index: _,
111             substs: _,
112             user_ty: _,
113         }) => {
114             for field in &**fields {
115                 visitor.visit_expr(&visitor.thir()[field.expr]);
116             }
117             if let Some(base) = base {
118                 visitor.visit_expr(&visitor.thir()[base.base]);
119             }
120         }
121         PlaceTypeAscription { source, user_ty: _ } | ValueTypeAscription { source, user_ty: _ } => {
122             visitor.visit_expr(&visitor.thir()[source])
123         }
124         Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {}
125         Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal),
126         StaticRef { literal, def_id: _ } => visitor.visit_const(literal),
127         InlineAsm { ref operands, template: _, options: _, line_spans: _ } => {
128             for op in &**operands {
129                 use InlineAsmOperand::*;
130                 match op {
131                     In { expr, reg: _ }
132                     | Out { expr: Some(expr), reg: _, late: _ }
133                     | InOut { expr, reg: _, late: _ }
134                     | SymFn { expr } => visitor.visit_expr(&visitor.thir()[*expr]),
135                     SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
136                         visitor.visit_expr(&visitor.thir()[*in_expr]);
137                         if let Some(out_expr) = out_expr {
138                             visitor.visit_expr(&visitor.thir()[*out_expr]);
139                         }
140                     }
141                     Out { expr: None, reg: _, late: _ }
142                     | Const { value: _, span: _ }
143                     | SymStatic { def_id: _ } => {}
144                 }
145             }
146         }
147         ThreadLocalRef(_) => {}
148         LlvmInlineAsm { ref outputs, ref inputs, asm: _ } => {
149             for &out_expr in &**outputs {
150                 visitor.visit_expr(&visitor.thir()[out_expr]);
151             }
152             for &in_expr in &**inputs {
153                 visitor.visit_expr(&visitor.thir()[in_expr]);
154             }
155         }
156         Yield { value } => visitor.visit_expr(&visitor.thir()[value]),
157     }
158 }
159
160 pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stmt<'tcx>) {
161     match &stmt.kind {
162         StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[*expr]),
163         StmtKind::Let {
164             initializer,
165             remainder_scope: _,
166             init_scope: _,
167             ref pattern,
168             lint_level: _,
169         } => {
170             if let Some(init) = initializer {
171                 visitor.visit_expr(&visitor.thir()[*init]);
172             }
173             visitor.visit_pat(pattern);
174         }
175     }
176 }
177
178 pub fn walk_block<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, block: &Block) {
179     for &stmt in &*block.stmts {
180         visitor.visit_stmt(&visitor.thir()[stmt]);
181     }
182     if let Some(expr) = block.expr {
183         visitor.visit_expr(&visitor.thir()[expr]);
184     }
185 }
186
187 pub fn walk_arm<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, arm: &Arm<'tcx>) {
188     match arm.guard {
189         Some(Guard::If(expr)) => visitor.visit_expr(&visitor.thir()[expr]),
190         Some(Guard::IfLet(ref pat, expr)) => {
191             visitor.visit_pat(pat);
192             visitor.visit_expr(&visitor.thir()[expr]);
193         }
194         None => {}
195     }
196     visitor.visit_pat(&arm.pattern);
197     visitor.visit_expr(&visitor.thir()[arm.body]);
198 }
199
200 pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'tcx>) {
201     use PatKind::*;
202     match pat.kind.as_ref() {
203         AscribeUserType { subpattern, ascription: _ }
204         | Deref { subpattern }
205         | Binding {
206             subpattern: Some(subpattern),
207             mutability: _,
208             mode: _,
209             var: _,
210             ty: _,
211             is_primary: _,
212             name: _,
213         } => visitor.visit_pat(&subpattern),
214         Binding { .. } | Wild => {}
215         Variant { subpatterns, adt_def: _, substs: _, variant_index: _ } | Leaf { subpatterns } => {
216             for subpattern in subpatterns {
217                 visitor.visit_pat(&subpattern.pattern);
218             }
219         }
220         Constant { value } => visitor.visit_const(value),
221         Range(range) => {
222             visitor.visit_const(range.lo);
223             visitor.visit_const(range.hi);
224         }
225         Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => {
226             for subpattern in prefix {
227                 visitor.visit_pat(&subpattern);
228             }
229             if let Some(pat) = slice {
230                 visitor.visit_pat(pat);
231             }
232             for subpattern in suffix {
233                 visitor.visit_pat(&subpattern);
234             }
235         }
236         Or { pats } => {
237             for pat in pats {
238                 visitor.visit_pat(&pat);
239             }
240         }
241     };
242 }