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