aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/expr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/expr.rs')
-rw-r--r--crates/ra_hir/src/expr.rs745
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 @@
1use std::ops::Index;
2use std::sync::Arc;
3
4use rustc_hash::FxHashMap;
5
6use ra_arena::{Arena, RawId, impl_arena_id};
7use ra_db::{LocalSyntaxPtr, Cancelable};
8use ra_syntax::ast::{self, AstNode, LoopBodyOwner, ArgListOwner, NameOwner};
9
10use crate::{Path, type_ref::{Mutability, TypeRef}, Name, HirDatabase, DefId, Def, name::AsName};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
13pub struct ExprId(RawId);
14impl_arena_id!(ExprId);
15
16/// The body of an item (function, const etc.).
17#[derive(Debug, Eq, PartialEq)]
18pub 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)]
39pub 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
47impl 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
57impl Index<ExprId> for Body {
58 type Output = Expr;
59
60 fn index(&self, expr: ExprId) -> &Expr {
61 &self.exprs[expr]
62 }
63}
64
65impl Index<PatId> for Body {
66 type Output = Pat;
67
68 fn index(&self, pat: PatId) -> &Pat {
69 &self.pats[pat]
70 }
71}
72
73impl 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)]
93pub 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
169pub type UnaryOp = ast::PrefixOp;
170
171#[derive(Debug, Clone, Eq, PartialEq)]
172pub struct MatchArm {
173 pub pats: Vec<PatId>,
174 // guard: Option<ExprId>, // TODO
175 pub expr: ExprId,
176}
177
178#[derive(Debug, Clone, Eq, PartialEq)]
179pub struct StructLitField {
180 pub name: Name,
181 pub expr: ExprId,
182}
183
184#[derive(Debug, Clone, Eq, PartialEq)]
185pub enum Statement {
186 Let {
187 pat: PatId,
188 type_ref: Option<TypeRef>,
189 initializer: Option<ExprId>,
190 },
191 Expr(ExprId),
192}
193
194impl 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)]
281pub struct PatId(RawId);
282impl_arena_id!(PatId);
283
284#[derive(Debug, Clone, Eq, PartialEq)]
285pub enum Pat {
286 Missing,
287 Bind {
288 name: Name,
289 },
290 TupleStruct {
291 path: Option<Path>,
292 args: Vec<PatId>,
293 },
294}
295
296impl 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
309pub(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
313struct 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
322impl 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
688pub(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
727pub(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}