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