diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-08-13 15:31:49 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-08-13 15:31:49 +0100 |
commit | e9926948ca267932ccc1341388bfd1b3fa88a001 (patch) | |
tree | cc4b797cb39a40b59e9e3d37178e8a1907f12358 /crates/hir_def/src/expr.rs | |
parent | 902f74c2697cc2a50de9067845814a2a852fccfd (diff) | |
parent | 50f8c1ebf23f634b68529603a917e3feeda457fa (diff) |
Merge #5747
5747: Rename crate r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/hir_def/src/expr.rs')
-rw-r--r-- | crates/hir_def/src/expr.rs | 420 |
1 files changed, 420 insertions, 0 deletions
diff --git a/crates/hir_def/src/expr.rs b/crates/hir_def/src/expr.rs new file mode 100644 index 000000000..c94b3a36f --- /dev/null +++ b/crates/hir_def/src/expr.rs | |||
@@ -0,0 +1,420 @@ | |||
1 | //! This module describes hir-level representation of expressions. | ||
2 | //! | ||
3 | //! This representaion is: | ||
4 | //! | ||
5 | //! 1. Identity-based. Each expression has an `id`, so we can distinguish | ||
6 | //! between different `1` in `1 + 1`. | ||
7 | //! 2. Independent of syntax. Though syntactic provenance information can be | ||
8 | //! attached separately via id-based side map. | ||
9 | //! 3. Unresolved. Paths are stored as sequences of names, and not as defs the | ||
10 | //! names refer to. | ||
11 | //! 4. Desugared. There's no `if let`. | ||
12 | //! | ||
13 | //! See also a neighboring `body` module. | ||
14 | |||
15 | use arena::{Idx, RawId}; | ||
16 | use hir_expand::name::Name; | ||
17 | use syntax::ast::RangeOp; | ||
18 | |||
19 | use crate::{ | ||
20 | builtin_type::{BuiltinFloat, BuiltinInt}, | ||
21 | path::{GenericArgs, Path}, | ||
22 | type_ref::{Mutability, Rawness, TypeRef}, | ||
23 | }; | ||
24 | |||
25 | pub type ExprId = Idx<Expr>; | ||
26 | pub(crate) fn dummy_expr_id() -> ExprId { | ||
27 | ExprId::from_raw(RawId::from(!0)) | ||
28 | } | ||
29 | |||
30 | pub type PatId = Idx<Pat>; | ||
31 | |||
32 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
33 | pub enum Literal { | ||
34 | String(String), | ||
35 | ByteString(Vec<u8>), | ||
36 | Char(char), | ||
37 | Bool(bool), | ||
38 | Int(u64, Option<BuiltinInt>), | ||
39 | Float(u64, Option<BuiltinFloat>), // FIXME: f64 is not Eq | ||
40 | } | ||
41 | |||
42 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
43 | pub enum Expr { | ||
44 | /// This is produced if the syntax tree does not have a required expression piece. | ||
45 | Missing, | ||
46 | Path(Path), | ||
47 | If { | ||
48 | condition: ExprId, | ||
49 | then_branch: ExprId, | ||
50 | else_branch: Option<ExprId>, | ||
51 | }, | ||
52 | Block { | ||
53 | statements: Vec<Statement>, | ||
54 | tail: Option<ExprId>, | ||
55 | label: Option<Name>, | ||
56 | }, | ||
57 | Loop { | ||
58 | body: ExprId, | ||
59 | label: Option<Name>, | ||
60 | }, | ||
61 | While { | ||
62 | condition: ExprId, | ||
63 | body: ExprId, | ||
64 | label: Option<Name>, | ||
65 | }, | ||
66 | For { | ||
67 | iterable: ExprId, | ||
68 | pat: PatId, | ||
69 | body: ExprId, | ||
70 | label: Option<Name>, | ||
71 | }, | ||
72 | Call { | ||
73 | callee: ExprId, | ||
74 | args: Vec<ExprId>, | ||
75 | }, | ||
76 | MethodCall { | ||
77 | receiver: ExprId, | ||
78 | method_name: Name, | ||
79 | args: Vec<ExprId>, | ||
80 | generic_args: Option<GenericArgs>, | ||
81 | }, | ||
82 | Match { | ||
83 | expr: ExprId, | ||
84 | arms: Vec<MatchArm>, | ||
85 | }, | ||
86 | Continue { | ||
87 | label: Option<Name>, | ||
88 | }, | ||
89 | Break { | ||
90 | expr: Option<ExprId>, | ||
91 | label: Option<Name>, | ||
92 | }, | ||
93 | Return { | ||
94 | expr: Option<ExprId>, | ||
95 | }, | ||
96 | RecordLit { | ||
97 | path: Option<Path>, | ||
98 | fields: Vec<RecordLitField>, | ||
99 | spread: Option<ExprId>, | ||
100 | }, | ||
101 | Field { | ||
102 | expr: ExprId, | ||
103 | name: Name, | ||
104 | }, | ||
105 | Await { | ||
106 | expr: ExprId, | ||
107 | }, | ||
108 | Try { | ||
109 | expr: ExprId, | ||
110 | }, | ||
111 | TryBlock { | ||
112 | body: ExprId, | ||
113 | }, | ||
114 | Cast { | ||
115 | expr: ExprId, | ||
116 | type_ref: TypeRef, | ||
117 | }, | ||
118 | Ref { | ||
119 | expr: ExprId, | ||
120 | rawness: Rawness, | ||
121 | mutability: Mutability, | ||
122 | }, | ||
123 | Box { | ||
124 | expr: ExprId, | ||
125 | }, | ||
126 | UnaryOp { | ||
127 | expr: ExprId, | ||
128 | op: UnaryOp, | ||
129 | }, | ||
130 | BinaryOp { | ||
131 | lhs: ExprId, | ||
132 | rhs: ExprId, | ||
133 | op: Option<BinaryOp>, | ||
134 | }, | ||
135 | Range { | ||
136 | lhs: Option<ExprId>, | ||
137 | rhs: Option<ExprId>, | ||
138 | range_type: RangeOp, | ||
139 | }, | ||
140 | Index { | ||
141 | base: ExprId, | ||
142 | index: ExprId, | ||
143 | }, | ||
144 | Lambda { | ||
145 | args: Vec<PatId>, | ||
146 | arg_types: Vec<Option<TypeRef>>, | ||
147 | ret_type: Option<TypeRef>, | ||
148 | body: ExprId, | ||
149 | }, | ||
150 | Tuple { | ||
151 | exprs: Vec<ExprId>, | ||
152 | }, | ||
153 | Unsafe { | ||
154 | body: ExprId, | ||
155 | }, | ||
156 | Array(Array), | ||
157 | Literal(Literal), | ||
158 | } | ||
159 | |||
160 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
161 | pub enum BinaryOp { | ||
162 | LogicOp(LogicOp), | ||
163 | ArithOp(ArithOp), | ||
164 | CmpOp(CmpOp), | ||
165 | Assignment { op: Option<ArithOp> }, | ||
166 | } | ||
167 | |||
168 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
169 | pub enum LogicOp { | ||
170 | And, | ||
171 | Or, | ||
172 | } | ||
173 | |||
174 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
175 | pub enum CmpOp { | ||
176 | Eq { negated: bool }, | ||
177 | Ord { ordering: Ordering, strict: bool }, | ||
178 | } | ||
179 | |||
180 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
181 | pub enum Ordering { | ||
182 | Less, | ||
183 | Greater, | ||
184 | } | ||
185 | |||
186 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
187 | pub enum ArithOp { | ||
188 | Add, | ||
189 | Mul, | ||
190 | Sub, | ||
191 | Div, | ||
192 | Rem, | ||
193 | Shl, | ||
194 | Shr, | ||
195 | BitXor, | ||
196 | BitOr, | ||
197 | BitAnd, | ||
198 | } | ||
199 | |||
200 | pub use syntax::ast::PrefixOp as UnaryOp; | ||
201 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
202 | pub enum Array { | ||
203 | ElementList(Vec<ExprId>), | ||
204 | Repeat { initializer: ExprId, repeat: ExprId }, | ||
205 | } | ||
206 | |||
207 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
208 | pub struct MatchArm { | ||
209 | pub pat: PatId, | ||
210 | pub guard: Option<ExprId>, | ||
211 | pub expr: ExprId, | ||
212 | } | ||
213 | |||
214 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
215 | pub struct RecordLitField { | ||
216 | pub name: Name, | ||
217 | pub expr: ExprId, | ||
218 | } | ||
219 | |||
220 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
221 | pub enum Statement { | ||
222 | Let { pat: PatId, type_ref: Option<TypeRef>, initializer: Option<ExprId> }, | ||
223 | Expr(ExprId), | ||
224 | } | ||
225 | |||
226 | impl Expr { | ||
227 | pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) { | ||
228 | match self { | ||
229 | Expr::Missing => {} | ||
230 | Expr::Path(_) => {} | ||
231 | Expr::If { condition, then_branch, else_branch } => { | ||
232 | f(*condition); | ||
233 | f(*then_branch); | ||
234 | if let Some(else_branch) = else_branch { | ||
235 | f(*else_branch); | ||
236 | } | ||
237 | } | ||
238 | Expr::Block { statements, tail, .. } => { | ||
239 | for stmt in statements { | ||
240 | match stmt { | ||
241 | Statement::Let { initializer, .. } => { | ||
242 | if let Some(expr) = initializer { | ||
243 | f(*expr); | ||
244 | } | ||
245 | } | ||
246 | Statement::Expr(e) => f(*e), | ||
247 | } | ||
248 | } | ||
249 | if let Some(expr) = tail { | ||
250 | f(*expr); | ||
251 | } | ||
252 | } | ||
253 | Expr::TryBlock { body } | Expr::Unsafe { body } => f(*body), | ||
254 | Expr::Loop { body, .. } => f(*body), | ||
255 | Expr::While { condition, body, .. } => { | ||
256 | f(*condition); | ||
257 | f(*body); | ||
258 | } | ||
259 | Expr::For { iterable, body, .. } => { | ||
260 | f(*iterable); | ||
261 | f(*body); | ||
262 | } | ||
263 | Expr::Call { callee, args } => { | ||
264 | f(*callee); | ||
265 | for arg in args { | ||
266 | f(*arg); | ||
267 | } | ||
268 | } | ||
269 | Expr::MethodCall { receiver, args, .. } => { | ||
270 | f(*receiver); | ||
271 | for arg in args { | ||
272 | f(*arg); | ||
273 | } | ||
274 | } | ||
275 | Expr::Match { expr, arms } => { | ||
276 | f(*expr); | ||
277 | for arm in arms { | ||
278 | f(arm.expr); | ||
279 | } | ||
280 | } | ||
281 | Expr::Continue { .. } => {} | ||
282 | Expr::Break { expr, .. } | Expr::Return { expr } => { | ||
283 | if let Some(expr) = expr { | ||
284 | f(*expr); | ||
285 | } | ||
286 | } | ||
287 | Expr::RecordLit { fields, spread, .. } => { | ||
288 | for field in fields { | ||
289 | f(field.expr); | ||
290 | } | ||
291 | if let Some(expr) = spread { | ||
292 | f(*expr); | ||
293 | } | ||
294 | } | ||
295 | Expr::Lambda { body, .. } => { | ||
296 | f(*body); | ||
297 | } | ||
298 | Expr::BinaryOp { lhs, rhs, .. } => { | ||
299 | f(*lhs); | ||
300 | f(*rhs); | ||
301 | } | ||
302 | Expr::Range { lhs, rhs, .. } => { | ||
303 | if let Some(lhs) = rhs { | ||
304 | f(*lhs); | ||
305 | } | ||
306 | if let Some(rhs) = lhs { | ||
307 | f(*rhs); | ||
308 | } | ||
309 | } | ||
310 | Expr::Index { base, index } => { | ||
311 | f(*base); | ||
312 | f(*index); | ||
313 | } | ||
314 | Expr::Field { expr, .. } | ||
315 | | Expr::Await { expr } | ||
316 | | Expr::Try { expr } | ||
317 | | Expr::Cast { expr, .. } | ||
318 | | Expr::Ref { expr, .. } | ||
319 | | Expr::UnaryOp { expr, .. } | ||
320 | | Expr::Box { expr } => { | ||
321 | f(*expr); | ||
322 | } | ||
323 | Expr::Tuple { exprs } => { | ||
324 | for expr in exprs { | ||
325 | f(*expr); | ||
326 | } | ||
327 | } | ||
328 | Expr::Array(a) => match a { | ||
329 | Array::ElementList(exprs) => { | ||
330 | for expr in exprs { | ||
331 | f(*expr); | ||
332 | } | ||
333 | } | ||
334 | Array::Repeat { initializer, repeat } => { | ||
335 | f(*initializer); | ||
336 | f(*repeat) | ||
337 | } | ||
338 | }, | ||
339 | Expr::Literal(_) => {} | ||
340 | } | ||
341 | } | ||
342 | } | ||
343 | |||
344 | /// Explicit binding annotations given in the HIR for a binding. Note | ||
345 | /// that this is not the final binding *mode* that we infer after type | ||
346 | /// inference. | ||
347 | #[derive(Clone, PartialEq, Eq, Debug, Copy)] | ||
348 | pub enum BindingAnnotation { | ||
349 | /// No binding annotation given: this means that the final binding mode | ||
350 | /// will depend on whether we have skipped through a `&` reference | ||
351 | /// when matching. For example, the `x` in `Some(x)` will have binding | ||
352 | /// mode `None`; if you do `let Some(x) = &Some(22)`, it will | ||
353 | /// ultimately be inferred to be by-reference. | ||
354 | Unannotated, | ||
355 | |||
356 | /// Annotated with `mut x` -- could be either ref or not, similar to `None`. | ||
357 | Mutable, | ||
358 | |||
359 | /// Annotated as `ref`, like `ref x` | ||
360 | Ref, | ||
361 | |||
362 | /// Annotated as `ref mut x`. | ||
363 | RefMut, | ||
364 | } | ||
365 | |||
366 | impl BindingAnnotation { | ||
367 | pub fn new(is_mutable: bool, is_ref: bool) -> Self { | ||
368 | match (is_mutable, is_ref) { | ||
369 | (true, true) => BindingAnnotation::RefMut, | ||
370 | (false, true) => BindingAnnotation::Ref, | ||
371 | (true, false) => BindingAnnotation::Mutable, | ||
372 | (false, false) => BindingAnnotation::Unannotated, | ||
373 | } | ||
374 | } | ||
375 | } | ||
376 | |||
377 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
378 | pub struct RecordFieldPat { | ||
379 | pub name: Name, | ||
380 | pub pat: PatId, | ||
381 | } | ||
382 | |||
383 | /// Close relative to rustc's hir::PatKind | ||
384 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
385 | pub enum Pat { | ||
386 | Missing, | ||
387 | Wild, | ||
388 | Tuple { args: Vec<PatId>, ellipsis: Option<usize> }, | ||
389 | Or(Vec<PatId>), | ||
390 | Record { path: Option<Path>, args: Vec<RecordFieldPat>, ellipsis: bool }, | ||
391 | Range { start: ExprId, end: ExprId }, | ||
392 | Slice { prefix: Vec<PatId>, slice: Option<PatId>, suffix: Vec<PatId> }, | ||
393 | Path(Path), | ||
394 | Lit(ExprId), | ||
395 | Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> }, | ||
396 | TupleStruct { path: Option<Path>, args: Vec<PatId>, ellipsis: Option<usize> }, | ||
397 | Ref { pat: PatId, mutability: Mutability }, | ||
398 | } | ||
399 | |||
400 | impl Pat { | ||
401 | pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) { | ||
402 | match self { | ||
403 | Pat::Range { .. } | Pat::Lit(..) | Pat::Path(..) | Pat::Wild | Pat::Missing => {} | ||
404 | Pat::Bind { subpat, .. } => { | ||
405 | subpat.iter().copied().for_each(f); | ||
406 | } | ||
407 | Pat::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => { | ||
408 | args.iter().copied().for_each(f); | ||
409 | } | ||
410 | Pat::Ref { pat, .. } => f(*pat), | ||
411 | Pat::Slice { prefix, slice, suffix } => { | ||
412 | let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter()); | ||
413 | total_iter.copied().for_each(f); | ||
414 | } | ||
415 | Pat::Record { args, .. } => { | ||
416 | args.iter().map(|f| f.pat).for_each(f); | ||
417 | } | ||
418 | } | ||
419 | } | ||
420 | } | ||