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