aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/expr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def/src/expr.rs')
-rw-r--r--crates/ra_hir_def/src/expr.rs421
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
15use hir_expand::name::Name;
16use ra_arena::{impl_arena_id, RawId};
17
18use 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)]
25pub struct ExprId(RawId);
26impl_arena_id!(ExprId);
27
28impl ExprId {
29 pub fn dummy() -> ExprId {
30 ExprId((!0).into())
31 }
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
35pub struct PatId(RawId);
36impl_arena_id!(PatId);
37
38#[derive(Debug, Clone, Eq, PartialEq)]
39pub 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)]
49pub 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)]
150pub 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)]
158pub enum LogicOp {
159 And,
160 Or,
161}
162
163#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
164pub enum CmpOp {
165 Eq { negated: bool },
166 Ord { ordering: Ordering, strict: bool },
167}
168
169#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
170pub enum Ordering {
171 Less,
172 Greater,
173}
174
175#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
176pub enum ArithOp {
177 Add,
178 Mul,
179 Sub,
180 Div,
181 Rem,
182 Shl,
183 Shr,
184 BitXor,
185 BitOr,
186 BitAnd,
187}
188
189pub use ra_syntax::ast::PrefixOp as UnaryOp;
190#[derive(Debug, Clone, Eq, PartialEq)]
191pub enum Array {
192 ElementList(Vec<ExprId>),
193 Repeat { initializer: ExprId, repeat: ExprId },
194}
195
196#[derive(Debug, Clone, Eq, PartialEq)]
197pub struct MatchArm {
198 pub pats: Vec<PatId>,
199 pub guard: Option<ExprId>,
200 pub expr: ExprId,
201}
202
203#[derive(Debug, Clone, Eq, PartialEq)]
204pub struct RecordLitField {
205 pub name: Name,
206 pub expr: ExprId,
207}
208
209#[derive(Debug, Clone, Eq, PartialEq)]
210pub enum Statement {
211 Let { pat: PatId, type_ref: Option<TypeRef>, initializer: Option<ExprId> },
212 Expr(ExprId),
213}
214
215impl 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)]
329pub 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
347impl 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)]
359pub 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)]
366pub 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
401impl 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}