diff options
Diffstat (limited to 'crates/ra_hir/src/expr.rs')
-rw-r--r-- | crates/ra_hir/src/expr.rs | 745 |
1 files changed, 745 insertions, 0 deletions
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs new file mode 100644 index 000000000..6866fc2ac --- /dev/null +++ b/crates/ra_hir/src/expr.rs | |||
@@ -0,0 +1,745 @@ | |||
1 | use std::ops::Index; | ||
2 | use std::sync::Arc; | ||
3 | |||
4 | use rustc_hash::FxHashMap; | ||
5 | |||
6 | use ra_arena::{Arena, RawId, impl_arena_id}; | ||
7 | use ra_db::{LocalSyntaxPtr, Cancelable}; | ||
8 | use ra_syntax::ast::{self, AstNode, LoopBodyOwner, ArgListOwner, NameOwner}; | ||
9 | |||
10 | use crate::{Path, type_ref::{Mutability, TypeRef}, Name, HirDatabase, DefId, Def, name::AsName}; | ||
11 | |||
12 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
13 | pub struct ExprId(RawId); | ||
14 | impl_arena_id!(ExprId); | ||
15 | |||
16 | /// The body of an item (function, const etc.). | ||
17 | #[derive(Debug, Eq, PartialEq)] | ||
18 | pub struct Body { | ||
19 | exprs: Arena<ExprId, Expr>, | ||
20 | pats: Arena<PatId, Pat>, | ||
21 | /// The patterns for the function's arguments. While the argument types are | ||
22 | /// part of the function signature, the patterns are not (they don't change | ||
23 | /// the external type of the function). | ||
24 | /// | ||
25 | /// If this `Body` is for the body of a constant, this will just be | ||
26 | /// empty. | ||
27 | args: Vec<PatId>, | ||
28 | /// The `ExprId` of the actual body expression. | ||
29 | body_expr: ExprId, | ||
30 | } | ||
31 | |||
32 | /// An item body together with the mapping from syntax nodes to HIR expression | ||
33 | /// IDs. This is needed to go from e.g. a position in a file to the HIR | ||
34 | /// expression containing it; but for type inference etc., we want to operate on | ||
35 | /// a structure that is agnostic to the actual positions of expressions in the | ||
36 | /// file, so that we don't recompute the type inference whenever some whitespace | ||
37 | /// is typed. | ||
38 | #[derive(Debug, Eq, PartialEq)] | ||
39 | pub struct BodySyntaxMapping { | ||
40 | body: Arc<Body>, | ||
41 | expr_syntax_mapping: FxHashMap<LocalSyntaxPtr, ExprId>, | ||
42 | expr_syntax_mapping_back: FxHashMap<ExprId, LocalSyntaxPtr>, | ||
43 | pat_syntax_mapping: FxHashMap<LocalSyntaxPtr, PatId>, | ||
44 | pat_syntax_mapping_back: FxHashMap<PatId, LocalSyntaxPtr>, | ||
45 | } | ||
46 | |||
47 | impl Body { | ||
48 | pub fn args(&self) -> &[PatId] { | ||
49 | &self.args | ||
50 | } | ||
51 | |||
52 | pub fn body_expr(&self) -> ExprId { | ||
53 | self.body_expr | ||
54 | } | ||
55 | } | ||
56 | |||
57 | impl Index<ExprId> for Body { | ||
58 | type Output = Expr; | ||
59 | |||
60 | fn index(&self, expr: ExprId) -> &Expr { | ||
61 | &self.exprs[expr] | ||
62 | } | ||
63 | } | ||
64 | |||
65 | impl Index<PatId> for Body { | ||
66 | type Output = Pat; | ||
67 | |||
68 | fn index(&self, pat: PatId) -> &Pat { | ||
69 | &self.pats[pat] | ||
70 | } | ||
71 | } | ||
72 | |||
73 | impl BodySyntaxMapping { | ||
74 | pub fn expr_syntax(&self, expr: ExprId) -> Option<LocalSyntaxPtr> { | ||
75 | self.expr_syntax_mapping_back.get(&expr).cloned() | ||
76 | } | ||
77 | pub fn syntax_expr(&self, ptr: LocalSyntaxPtr) -> Option<ExprId> { | ||
78 | self.expr_syntax_mapping.get(&ptr).cloned() | ||
79 | } | ||
80 | pub fn pat_syntax(&self, pat: PatId) -> Option<LocalSyntaxPtr> { | ||
81 | self.pat_syntax_mapping_back.get(&pat).cloned() | ||
82 | } | ||
83 | pub fn syntax_pat(&self, ptr: LocalSyntaxPtr) -> Option<PatId> { | ||
84 | self.pat_syntax_mapping.get(&ptr).cloned() | ||
85 | } | ||
86 | |||
87 | pub fn body(&self) -> &Arc<Body> { | ||
88 | &self.body | ||
89 | } | ||
90 | } | ||
91 | |||
92 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
93 | pub enum Expr { | ||
94 | /// This is produced if syntax tree does not have a required expression piece. | ||
95 | Missing, | ||
96 | Path(Path), | ||
97 | If { | ||
98 | condition: ExprId, | ||
99 | then_branch: ExprId, | ||
100 | else_branch: Option<ExprId>, | ||
101 | }, | ||
102 | Block { | ||
103 | statements: Vec<Statement>, | ||
104 | tail: Option<ExprId>, | ||
105 | }, | ||
106 | Loop { | ||
107 | body: ExprId, | ||
108 | }, | ||
109 | While { | ||
110 | condition: ExprId, | ||
111 | body: ExprId, | ||
112 | }, | ||
113 | For { | ||
114 | iterable: ExprId, | ||
115 | pat: PatId, | ||
116 | body: ExprId, | ||
117 | }, | ||
118 | Call { | ||
119 | callee: ExprId, | ||
120 | args: Vec<ExprId>, | ||
121 | }, | ||
122 | MethodCall { | ||
123 | receiver: ExprId, | ||
124 | method_name: Name, | ||
125 | args: Vec<ExprId>, | ||
126 | }, | ||
127 | Match { | ||
128 | expr: ExprId, | ||
129 | arms: Vec<MatchArm>, | ||
130 | }, | ||
131 | Continue, | ||
132 | Break { | ||
133 | expr: Option<ExprId>, | ||
134 | }, | ||
135 | Return { | ||
136 | expr: Option<ExprId>, | ||
137 | }, | ||
138 | StructLit { | ||
139 | path: Option<Path>, | ||
140 | fields: Vec<StructLitField>, | ||
141 | spread: Option<ExprId>, | ||
142 | }, | ||
143 | Field { | ||
144 | expr: ExprId, | ||
145 | name: Name, | ||
146 | }, | ||
147 | Try { | ||
148 | expr: ExprId, | ||
149 | }, | ||
150 | Cast { | ||
151 | expr: ExprId, | ||
152 | type_ref: TypeRef, | ||
153 | }, | ||
154 | Ref { | ||
155 | expr: ExprId, | ||
156 | mutability: Mutability, | ||
157 | }, | ||
158 | UnaryOp { | ||
159 | expr: ExprId, | ||
160 | op: Option<UnaryOp>, | ||
161 | }, | ||
162 | Lambda { | ||
163 | args: Vec<PatId>, | ||
164 | arg_types: Vec<Option<TypeRef>>, | ||
165 | body: ExprId, | ||
166 | }, | ||
167 | } | ||
168 | |||
169 | pub type UnaryOp = ast::PrefixOp; | ||
170 | |||
171 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
172 | pub struct MatchArm { | ||
173 | pub pats: Vec<PatId>, | ||
174 | // guard: Option<ExprId>, // TODO | ||
175 | pub expr: ExprId, | ||
176 | } | ||
177 | |||
178 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
179 | pub struct StructLitField { | ||
180 | pub name: Name, | ||
181 | pub expr: ExprId, | ||
182 | } | ||
183 | |||
184 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
185 | pub enum Statement { | ||
186 | Let { | ||
187 | pat: PatId, | ||
188 | type_ref: Option<TypeRef>, | ||
189 | initializer: Option<ExprId>, | ||
190 | }, | ||
191 | Expr(ExprId), | ||
192 | } | ||
193 | |||
194 | impl Expr { | ||
195 | pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) { | ||
196 | match self { | ||
197 | Expr::Missing => {} | ||
198 | Expr::Path(_) => {} | ||
199 | Expr::If { | ||
200 | condition, | ||
201 | then_branch, | ||
202 | else_branch, | ||
203 | } => { | ||
204 | f(*condition); | ||
205 | f(*then_branch); | ||
206 | if let Some(else_branch) = else_branch { | ||
207 | f(*else_branch); | ||
208 | } | ||
209 | } | ||
210 | Expr::Block { statements, tail } => { | ||
211 | for stmt in statements { | ||
212 | match stmt { | ||
213 | Statement::Let { initializer, .. } => { | ||
214 | if let Some(expr) = initializer { | ||
215 | f(*expr); | ||
216 | } | ||
217 | } | ||
218 | Statement::Expr(e) => f(*e), | ||
219 | } | ||
220 | } | ||
221 | if let Some(expr) = tail { | ||
222 | f(*expr); | ||
223 | } | ||
224 | } | ||
225 | Expr::Loop { body } => f(*body), | ||
226 | Expr::While { condition, body } => { | ||
227 | f(*condition); | ||
228 | f(*body); | ||
229 | } | ||
230 | Expr::For { iterable, body, .. } => { | ||
231 | f(*iterable); | ||
232 | f(*body); | ||
233 | } | ||
234 | Expr::Call { callee, args } => { | ||
235 | f(*callee); | ||
236 | for arg in args { | ||
237 | f(*arg); | ||
238 | } | ||
239 | } | ||
240 | Expr::MethodCall { receiver, args, .. } => { | ||
241 | f(*receiver); | ||
242 | for arg in args { | ||
243 | f(*arg); | ||
244 | } | ||
245 | } | ||
246 | Expr::Match { expr, arms } => { | ||
247 | f(*expr); | ||
248 | for arm in arms { | ||
249 | f(arm.expr); | ||
250 | } | ||
251 | } | ||
252 | Expr::Continue => {} | ||
253 | Expr::Break { expr } | Expr::Return { expr } => { | ||
254 | if let Some(expr) = expr { | ||
255 | f(*expr); | ||
256 | } | ||
257 | } | ||
258 | Expr::StructLit { fields, spread, .. } => { | ||
259 | for field in fields { | ||
260 | f(field.expr); | ||
261 | } | ||
262 | if let Some(expr) = spread { | ||
263 | f(*expr); | ||
264 | } | ||
265 | } | ||
266 | Expr::Lambda { body, .. } => { | ||
267 | f(*body); | ||
268 | } | ||
269 | Expr::Field { expr, .. } | ||
270 | | Expr::Try { expr } | ||
271 | | Expr::Cast { expr, .. } | ||
272 | | Expr::Ref { expr, .. } | ||
273 | | Expr::UnaryOp { expr, .. } => { | ||
274 | f(*expr); | ||
275 | } | ||
276 | } | ||
277 | } | ||
278 | } | ||
279 | |||
280 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
281 | pub struct PatId(RawId); | ||
282 | impl_arena_id!(PatId); | ||
283 | |||
284 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
285 | pub enum Pat { | ||
286 | Missing, | ||
287 | Bind { | ||
288 | name: Name, | ||
289 | }, | ||
290 | TupleStruct { | ||
291 | path: Option<Path>, | ||
292 | args: Vec<PatId>, | ||
293 | }, | ||
294 | } | ||
295 | |||
296 | impl Pat { | ||
297 | pub fn walk_child_pats(&self, f: impl FnMut(PatId)) { | ||
298 | match self { | ||
299 | Pat::Missing | Pat::Bind { .. } => {} | ||
300 | Pat::TupleStruct { args, .. } => { | ||
301 | args.iter().map(|pat| *pat).for_each(f); | ||
302 | } | ||
303 | } | ||
304 | } | ||
305 | } | ||
306 | |||
307 | // Queries | ||
308 | |||
309 | pub(crate) fn body_hir(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<Body>> { | ||
310 | Ok(Arc::clone(&body_syntax_mapping(db, def_id)?.body)) | ||
311 | } | ||
312 | |||
313 | struct ExprCollector { | ||
314 | exprs: Arena<ExprId, Expr>, | ||
315 | pats: Arena<PatId, Pat>, | ||
316 | expr_syntax_mapping: FxHashMap<LocalSyntaxPtr, ExprId>, | ||
317 | expr_syntax_mapping_back: FxHashMap<ExprId, LocalSyntaxPtr>, | ||
318 | pat_syntax_mapping: FxHashMap<LocalSyntaxPtr, PatId>, | ||
319 | pat_syntax_mapping_back: FxHashMap<PatId, LocalSyntaxPtr>, | ||
320 | } | ||
321 | |||
322 | impl ExprCollector { | ||
323 | fn new() -> Self { | ||
324 | ExprCollector { | ||
325 | exprs: Arena::default(), | ||
326 | pats: Arena::default(), | ||
327 | expr_syntax_mapping: FxHashMap::default(), | ||
328 | expr_syntax_mapping_back: FxHashMap::default(), | ||
329 | pat_syntax_mapping: FxHashMap::default(), | ||
330 | pat_syntax_mapping_back: FxHashMap::default(), | ||
331 | } | ||
332 | } | ||
333 | |||
334 | fn alloc_expr(&mut self, expr: Expr, syntax_ptr: LocalSyntaxPtr) -> ExprId { | ||
335 | let id = self.exprs.alloc(expr); | ||
336 | self.expr_syntax_mapping.insert(syntax_ptr, id); | ||
337 | self.expr_syntax_mapping_back.insert(id, syntax_ptr); | ||
338 | id | ||
339 | } | ||
340 | |||
341 | fn alloc_pat(&mut self, pat: Pat, syntax_ptr: LocalSyntaxPtr) -> PatId { | ||
342 | let id = self.pats.alloc(pat); | ||
343 | self.pat_syntax_mapping.insert(syntax_ptr, id); | ||
344 | self.pat_syntax_mapping_back.insert(id, syntax_ptr); | ||
345 | id | ||
346 | } | ||
347 | |||
348 | fn empty_block(&mut self) -> ExprId { | ||
349 | let block = Expr::Block { | ||
350 | statements: Vec::new(), | ||
351 | tail: None, | ||
352 | }; | ||
353 | self.exprs.alloc(block) | ||
354 | } | ||
355 | |||
356 | fn collect_expr(&mut self, expr: ast::Expr) -> ExprId { | ||
357 | let syntax_ptr = LocalSyntaxPtr::new(expr.syntax()); | ||
358 | match expr { | ||
359 | ast::Expr::IfExpr(e) => { | ||
360 | if let Some(pat) = e.condition().and_then(|c| c.pat()) { | ||
361 | // if let -- desugar to match | ||
362 | let pat = self.collect_pat(pat); | ||
363 | let match_expr = | ||
364 | self.collect_expr_opt(e.condition().expect("checked above").expr()); | ||
365 | let then_branch = self.collect_block_opt(e.then_branch()); | ||
366 | let else_branch = e | ||
367 | .else_branch() | ||
368 | .map(|e| self.collect_block(e)) | ||
369 | .unwrap_or_else(|| self.empty_block()); | ||
370 | let placeholder_pat = self.pats.alloc(Pat::Missing); | ||
371 | let arms = vec![ | ||
372 | MatchArm { | ||
373 | pats: vec![pat], | ||
374 | expr: then_branch, | ||
375 | }, | ||
376 | MatchArm { | ||
377 | pats: vec![placeholder_pat], | ||
378 | expr: else_branch, | ||
379 | }, | ||
380 | ]; | ||
381 | self.alloc_expr( | ||
382 | Expr::Match { | ||
383 | expr: match_expr, | ||
384 | arms, | ||
385 | }, | ||
386 | syntax_ptr, | ||
387 | ) | ||
388 | } else { | ||
389 | let condition = self.collect_expr_opt(e.condition().and_then(|c| c.expr())); | ||
390 | let then_branch = self.collect_block_opt(e.then_branch()); | ||
391 | let else_branch = e.else_branch().map(|e| self.collect_block(e)); | ||
392 | self.alloc_expr( | ||
393 | Expr::If { | ||
394 | condition, | ||
395 | then_branch, | ||
396 | else_branch, | ||
397 | }, | ||
398 | syntax_ptr, | ||
399 | ) | ||
400 | } | ||
401 | } | ||
402 | ast::Expr::BlockExpr(e) => self.collect_block_opt(e.block()), | ||
403 | ast::Expr::LoopExpr(e) => { | ||
404 | let body = self.collect_block_opt(e.loop_body()); | ||
405 | self.alloc_expr(Expr::Loop { body }, syntax_ptr) | ||
406 | } | ||
407 | ast::Expr::WhileExpr(e) => { | ||
408 | let condition = if let Some(condition) = e.condition() { | ||
409 | if condition.pat().is_none() { | ||
410 | self.collect_expr_opt(condition.expr()) | ||
411 | } else { | ||
412 | // TODO handle while let | ||
413 | return self.alloc_expr(Expr::Missing, syntax_ptr); | ||
414 | } | ||
415 | } else { | ||
416 | self.exprs.alloc(Expr::Missing) | ||
417 | }; | ||
418 | let body = self.collect_block_opt(e.loop_body()); | ||
419 | self.alloc_expr(Expr::While { condition, body }, syntax_ptr) | ||
420 | } | ||
421 | ast::Expr::ForExpr(e) => { | ||
422 | let iterable = self.collect_expr_opt(e.iterable()); | ||
423 | let pat = self.collect_pat_opt(e.pat()); | ||
424 | let body = self.collect_block_opt(e.loop_body()); | ||
425 | self.alloc_expr( | ||
426 | Expr::For { | ||
427 | iterable, | ||
428 | pat, | ||
429 | body, | ||
430 | }, | ||
431 | syntax_ptr, | ||
432 | ) | ||
433 | } | ||
434 | ast::Expr::CallExpr(e) => { | ||
435 | let callee = self.collect_expr_opt(e.expr()); | ||
436 | let args = if let Some(arg_list) = e.arg_list() { | ||
437 | arg_list.args().map(|e| self.collect_expr(e)).collect() | ||
438 | } else { | ||
439 | Vec::new() | ||
440 | }; | ||
441 | self.alloc_expr(Expr::Call { callee, args }, syntax_ptr) | ||
442 | } | ||
443 | ast::Expr::MethodCallExpr(e) => { | ||
444 | let receiver = self.collect_expr_opt(e.expr()); | ||
445 | let args = if let Some(arg_list) = e.arg_list() { | ||
446 | arg_list.args().map(|e| self.collect_expr(e)).collect() | ||
447 | } else { | ||
448 | Vec::new() | ||
449 | }; | ||
450 | let method_name = e | ||
451 | .name_ref() | ||
452 | .map(|nr| nr.as_name()) | ||
453 | .unwrap_or_else(Name::missing); | ||
454 | self.alloc_expr( | ||
455 | Expr::MethodCall { | ||
456 | receiver, | ||
457 | method_name, | ||
458 | args, | ||
459 | }, | ||
460 | syntax_ptr, | ||
461 | ) | ||
462 | } | ||
463 | ast::Expr::MatchExpr(e) => { | ||
464 | let expr = self.collect_expr_opt(e.expr()); | ||
465 | let arms = if let Some(match_arm_list) = e.match_arm_list() { | ||
466 | match_arm_list | ||
467 | .arms() | ||
468 | .map(|arm| MatchArm { | ||
469 | pats: arm.pats().map(|p| self.collect_pat(p)).collect(), | ||
470 | expr: self.collect_expr_opt(arm.expr()), | ||
471 | }) | ||
472 | .collect() | ||
473 | } else { | ||
474 | Vec::new() | ||
475 | }; | ||
476 | self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr) | ||
477 | } | ||
478 | ast::Expr::PathExpr(e) => { | ||
479 | let path = e | ||
480 | .path() | ||
481 | .and_then(Path::from_ast) | ||
482 | .map(Expr::Path) | ||
483 | .unwrap_or(Expr::Missing); | ||
484 | self.alloc_expr(path, syntax_ptr) | ||
485 | } | ||
486 | ast::Expr::ContinueExpr(_e) => { | ||
487 | // TODO: labels | ||
488 | self.alloc_expr(Expr::Continue, syntax_ptr) | ||
489 | } | ||
490 | ast::Expr::BreakExpr(e) => { | ||
491 | let expr = e.expr().map(|e| self.collect_expr(e)); | ||
492 | self.alloc_expr(Expr::Break { expr }, syntax_ptr) | ||
493 | } | ||
494 | ast::Expr::ParenExpr(e) => { | ||
495 | let inner = self.collect_expr_opt(e.expr()); | ||
496 | // make the paren expr point to the inner expression as well | ||
497 | self.expr_syntax_mapping.insert(syntax_ptr, inner); | ||
498 | inner | ||
499 | } | ||
500 | ast::Expr::ReturnExpr(e) => { | ||
501 | let expr = e.expr().map(|e| self.collect_expr(e)); | ||
502 | self.alloc_expr(Expr::Return { expr }, syntax_ptr) | ||
503 | } | ||
504 | ast::Expr::StructLit(e) => { | ||
505 | let path = e.path().and_then(Path::from_ast); | ||
506 | let fields = if let Some(nfl) = e.named_field_list() { | ||
507 | nfl.fields() | ||
508 | .map(|field| StructLitField { | ||
509 | name: field | ||
510 | .name_ref() | ||
511 | .map(|nr| nr.as_name()) | ||
512 | .unwrap_or_else(Name::missing), | ||
513 | expr: if let Some(e) = field.expr() { | ||
514 | self.collect_expr(e) | ||
515 | } else if let Some(nr) = field.name_ref() { | ||
516 | // field shorthand | ||
517 | let id = self.exprs.alloc(Expr::Path(Path::from_name_ref(nr))); | ||
518 | self.expr_syntax_mapping | ||
519 | .insert(LocalSyntaxPtr::new(nr.syntax()), id); | ||
520 | self.expr_syntax_mapping_back | ||
521 | .insert(id, LocalSyntaxPtr::new(nr.syntax())); | ||
522 | id | ||
523 | } else { | ||
524 | self.exprs.alloc(Expr::Missing) | ||
525 | }, | ||
526 | }) | ||
527 | .collect() | ||
528 | } else { | ||
529 | Vec::new() | ||
530 | }; | ||
531 | let spread = e.spread().map(|s| self.collect_expr(s)); | ||
532 | self.alloc_expr( | ||
533 | Expr::StructLit { | ||
534 | path, | ||
535 | fields, | ||
536 | spread, | ||
537 | }, | ||
538 | syntax_ptr, | ||
539 | ) | ||
540 | } | ||
541 | ast::Expr::FieldExpr(e) => { | ||
542 | let expr = self.collect_expr_opt(e.expr()); | ||
543 | let name = e | ||
544 | .name_ref() | ||
545 | .map(|nr| nr.as_name()) | ||
546 | .unwrap_or_else(Name::missing); | ||
547 | self.alloc_expr(Expr::Field { expr, name }, syntax_ptr) | ||
548 | } | ||
549 | ast::Expr::TryExpr(e) => { | ||
550 | let expr = self.collect_expr_opt(e.expr()); | ||
551 | self.alloc_expr(Expr::Try { expr }, syntax_ptr) | ||
552 | } | ||
553 | ast::Expr::CastExpr(e) => { | ||
554 | let expr = self.collect_expr_opt(e.expr()); | ||
555 | let type_ref = TypeRef::from_ast_opt(e.type_ref()); | ||
556 | self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr) | ||
557 | } | ||
558 | ast::Expr::RefExpr(e) => { | ||
559 | let expr = self.collect_expr_opt(e.expr()); | ||
560 | let mutability = Mutability::from_mutable(e.is_mut()); | ||
561 | self.alloc_expr(Expr::Ref { expr, mutability }, syntax_ptr) | ||
562 | } | ||
563 | ast::Expr::PrefixExpr(e) => { | ||
564 | let expr = self.collect_expr_opt(e.expr()); | ||
565 | let op = e.op(); | ||
566 | self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr) | ||
567 | } | ||
568 | ast::Expr::LambdaExpr(e) => { | ||
569 | let mut args = Vec::new(); | ||
570 | let mut arg_types = Vec::new(); | ||
571 | if let Some(pl) = e.param_list() { | ||
572 | for param in pl.params() { | ||
573 | let pat = self.collect_pat_opt(param.pat()); | ||
574 | let type_ref = param.type_ref().map(TypeRef::from_ast); | ||
575 | args.push(pat); | ||
576 | arg_types.push(type_ref); | ||
577 | } | ||
578 | } | ||
579 | let body = self.collect_expr_opt(e.body()); | ||
580 | self.alloc_expr( | ||
581 | Expr::Lambda { | ||
582 | args, | ||
583 | arg_types, | ||
584 | body, | ||
585 | }, | ||
586 | syntax_ptr, | ||
587 | ) | ||
588 | } | ||
589 | |||
590 | // TODO implement HIR for these: | ||
591 | ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
592 | ast::Expr::IndexExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
593 | ast::Expr::TupleExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
594 | ast::Expr::ArrayExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
595 | ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
596 | ast::Expr::BinExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
597 | ast::Expr::Literal(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
598 | } | ||
599 | } | ||
600 | |||
601 | fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId { | ||
602 | if let Some(expr) = expr { | ||
603 | self.collect_expr(expr) | ||
604 | } else { | ||
605 | self.exprs.alloc(Expr::Missing) | ||
606 | } | ||
607 | } | ||
608 | |||
609 | fn collect_block(&mut self, block: ast::Block) -> ExprId { | ||
610 | let statements = block | ||
611 | .statements() | ||
612 | .map(|s| match s { | ||
613 | ast::Stmt::LetStmt(stmt) => { | ||
614 | let pat = self.collect_pat_opt(stmt.pat()); | ||
615 | let type_ref = stmt.type_ref().map(TypeRef::from_ast); | ||
616 | let initializer = stmt.initializer().map(|e| self.collect_expr(e)); | ||
617 | Statement::Let { | ||
618 | pat, | ||
619 | type_ref, | ||
620 | initializer, | ||
621 | } | ||
622 | } | ||
623 | ast::Stmt::ExprStmt(stmt) => Statement::Expr(self.collect_expr_opt(stmt.expr())), | ||
624 | }) | ||
625 | .collect(); | ||
626 | let tail = block.expr().map(|e| self.collect_expr(e)); | ||
627 | self.alloc_expr( | ||
628 | Expr::Block { statements, tail }, | ||
629 | LocalSyntaxPtr::new(block.syntax()), | ||
630 | ) | ||
631 | } | ||
632 | |||
633 | fn collect_block_opt(&mut self, block: Option<ast::Block>) -> ExprId { | ||
634 | if let Some(block) = block { | ||
635 | self.collect_block(block) | ||
636 | } else { | ||
637 | self.exprs.alloc(Expr::Missing) | ||
638 | } | ||
639 | } | ||
640 | |||
641 | fn collect_pat(&mut self, pat: ast::Pat) -> PatId { | ||
642 | let syntax_ptr = LocalSyntaxPtr::new(pat.syntax()); | ||
643 | match pat { | ||
644 | ast::Pat::BindPat(bp) => { | ||
645 | let name = bp | ||
646 | .name() | ||
647 | .map(|nr| nr.as_name()) | ||
648 | .unwrap_or_else(Name::missing); | ||
649 | self.alloc_pat(Pat::Bind { name }, syntax_ptr) | ||
650 | } | ||
651 | ast::Pat::TupleStructPat(p) => { | ||
652 | let path = p.path().and_then(Path::from_ast); | ||
653 | let args = p.args().map(|p| self.collect_pat(p)).collect(); | ||
654 | self.alloc_pat(Pat::TupleStruct { path, args }, syntax_ptr) | ||
655 | } | ||
656 | _ => { | ||
657 | // TODO | ||
658 | self.alloc_pat(Pat::Missing, syntax_ptr) | ||
659 | } | ||
660 | } | ||
661 | } | ||
662 | |||
663 | fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId { | ||
664 | if let Some(pat) = pat { | ||
665 | self.collect_pat(pat) | ||
666 | } else { | ||
667 | self.pats.alloc(Pat::Missing) | ||
668 | } | ||
669 | } | ||
670 | |||
671 | fn into_body_syntax_mapping(self, args: Vec<PatId>, body_expr: ExprId) -> BodySyntaxMapping { | ||
672 | let body = Body { | ||
673 | exprs: self.exprs, | ||
674 | pats: self.pats, | ||
675 | args, | ||
676 | body_expr, | ||
677 | }; | ||
678 | BodySyntaxMapping { | ||
679 | body: Arc::new(body), | ||
680 | expr_syntax_mapping: self.expr_syntax_mapping, | ||
681 | expr_syntax_mapping_back: self.expr_syntax_mapping_back, | ||
682 | pat_syntax_mapping: self.pat_syntax_mapping, | ||
683 | pat_syntax_mapping_back: self.pat_syntax_mapping_back, | ||
684 | } | ||
685 | } | ||
686 | } | ||
687 | |||
688 | pub(crate) fn collect_fn_body_syntax(node: ast::FnDef) -> BodySyntaxMapping { | ||
689 | let mut collector = ExprCollector::new(); | ||
690 | |||
691 | let args = if let Some(param_list) = node.param_list() { | ||
692 | let mut args = Vec::new(); | ||
693 | |||
694 | if let Some(self_param) = param_list.self_param() { | ||
695 | let self_param = LocalSyntaxPtr::new( | ||
696 | self_param | ||
697 | .self_kw() | ||
698 | .expect("self param without self keyword") | ||
699 | .syntax(), | ||
700 | ); | ||
701 | let arg = collector.alloc_pat( | ||
702 | Pat::Bind { | ||
703 | name: Name::self_param(), | ||
704 | }, | ||
705 | self_param, | ||
706 | ); | ||
707 | args.push(arg); | ||
708 | } | ||
709 | |||
710 | for param in param_list.params() { | ||
711 | let pat = if let Some(pat) = param.pat() { | ||
712 | pat | ||
713 | } else { | ||
714 | continue; | ||
715 | }; | ||
716 | args.push(collector.collect_pat(pat)); | ||
717 | } | ||
718 | args | ||
719 | } else { | ||
720 | Vec::new() | ||
721 | }; | ||
722 | |||
723 | let body = collector.collect_block_opt(node.body()); | ||
724 | collector.into_body_syntax_mapping(args, body) | ||
725 | } | ||
726 | |||
727 | pub(crate) fn body_syntax_mapping( | ||
728 | db: &impl HirDatabase, | ||
729 | def_id: DefId, | ||
730 | ) -> Cancelable<Arc<BodySyntaxMapping>> { | ||
731 | let def = def_id.resolve(db)?; | ||
732 | |||
733 | let body_syntax_mapping = match def { | ||
734 | Def::Function(f) => { | ||
735 | let node = f.syntax(db); | ||
736 | let node = node.borrowed(); | ||
737 | |||
738 | collect_fn_body_syntax(node) | ||
739 | } | ||
740 | // TODO: consts, etc. | ||
741 | _ => panic!("Trying to get body for item type without body"), | ||
742 | }; | ||
743 | |||
744 | Ok(Arc::new(body_syntax_mapping)) | ||
745 | } | ||