aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/expr.rs
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-01-05 21:37:59 +0000
committerFlorian Diebold <[email protected]>2019-01-05 23:29:36 +0000
commit8e3e5ab2c81f238ea4e731f55eac79b74d9d84c3 (patch)
treee0388878b4d94ae71fbf82d3e3163c49c8e69c16 /crates/ra_hir/src/expr.rs
parent136aba1cf32646278c4034541ee415f656f8bb5e (diff)
Make FnScopes use hir::Expr
This was a bit complicated. I've added a wrapper type for now that does the LocalSyntaxPtr <-> ExprId translation; we might want to get rid of that or give it a nicer interface.
Diffstat (limited to 'crates/ra_hir/src/expr.rs')
-rw-r--r--crates/ra_hir/src/expr.rs363
1 files changed, 298 insertions, 65 deletions
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index 5cdcca082..5cf0f5e3f 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -4,7 +4,7 @@ use rustc_hash::FxHashMap;
4 4
5use ra_arena::{Arena, RawId, impl_arena_id}; 5use ra_arena::{Arena, RawId, impl_arena_id};
6use ra_db::{LocalSyntaxPtr, Cancelable}; 6use ra_db::{LocalSyntaxPtr, Cancelable};
7use ra_syntax::ast::{self, AstNode, LoopBodyOwner, ArgListOwner}; 7use ra_syntax::ast::{self, AstNode, LoopBodyOwner, ArgListOwner, NameOwner};
8 8
9use crate::{Path, type_ref::{Mutability, TypeRef}, Name, HirDatabase, DefId, Def, name::AsName}; 9use crate::{Path, type_ref::{Mutability, TypeRef}, Name, HirDatabase, DefId, Def, name::AsName};
10 10
@@ -21,7 +21,7 @@ pub struct Body {
21 /// part of the function signature, the patterns are not (they don't change 21 /// part of the function signature, the patterns are not (they don't change
22 /// the external type of the function). 22 /// the external type of the function).
23 /// 23 ///
24 /// If this `ExprTable` is for the body of a constant, this will just be 24 /// If this `Body` is for the body of a constant, this will just be
25 /// empty. 25 /// empty.
26 args: Vec<PatId>, 26 args: Vec<PatId>,
27 /// The `ExprId` of the actual body expression. 27 /// The `ExprId` of the actual body expression.
@@ -43,6 +43,43 @@ pub struct BodySyntaxMapping {
43 pat_syntax_mapping_back: FxHashMap<PatId, LocalSyntaxPtr>, 43 pat_syntax_mapping_back: FxHashMap<PatId, LocalSyntaxPtr>,
44} 44}
45 45
46impl Body {
47 pub fn expr(&self, expr: ExprId) -> &Expr {
48 &self.exprs[expr]
49 }
50
51 pub fn pat(&self, pat: PatId) -> &Pat {
52 &self.pats[pat]
53 }
54
55 pub fn args(&self) -> &[PatId] {
56 &self.args
57 }
58
59 pub fn body_expr(&self) -> ExprId {
60 self.body_expr
61 }
62}
63
64impl BodySyntaxMapping {
65 pub fn expr_syntax(&self, expr: ExprId) -> Option<LocalSyntaxPtr> {
66 self.expr_syntax_mapping_back.get(&expr).cloned()
67 }
68 pub fn syntax_expr(&self, ptr: LocalSyntaxPtr) -> Option<ExprId> {
69 self.expr_syntax_mapping.get(&ptr).cloned()
70 }
71 pub fn pat_syntax(&self, pat: PatId) -> Option<LocalSyntaxPtr> {
72 self.pat_syntax_mapping_back.get(&pat).cloned()
73 }
74 pub fn syntax_pat(&self, ptr: LocalSyntaxPtr) -> Option<PatId> {
75 self.pat_syntax_mapping.get(&ptr).cloned()
76 }
77
78 pub fn body(&self) -> &Arc<Body> {
79 &self.body
80 }
81}
82
46#[derive(Debug, Clone, Eq, PartialEq)] 83#[derive(Debug, Clone, Eq, PartialEq)]
47pub enum Expr { 84pub enum Expr {
48 /// This is produced if syntax tree does not have a required expression piece. 85 /// This is produced if syntax tree does not have a required expression piece.
@@ -113,21 +150,26 @@ pub enum Expr {
113 expr: ExprId, 150 expr: ExprId,
114 op: Option<UnaryOp>, 151 op: Option<UnaryOp>,
115 }, 152 },
153 Lambda {
154 args: Vec<PatId>,
155 arg_types: Vec<Option<TypeRef>>,
156 body: ExprId,
157 },
116} 158}
117 159
118pub type UnaryOp = ast::PrefixOp; 160pub type UnaryOp = ast::PrefixOp;
119 161
120#[derive(Debug, Clone, Eq, PartialEq)] 162#[derive(Debug, Clone, Eq, PartialEq)]
121pub struct MatchArm { 163pub struct MatchArm {
122 pats: Vec<PatId>, 164 pub pats: Vec<PatId>,
123 // guard: Option<ExprId>, // TODO 165 // guard: Option<ExprId>, // TODO
124 expr: ExprId, 166 pub expr: ExprId,
125} 167}
126 168
127#[derive(Debug, Clone, Eq, PartialEq)] 169#[derive(Debug, Clone, Eq, PartialEq)]
128pub struct StructLitField { 170pub struct StructLitField {
129 name: Name, 171 pub name: Name,
130 expr: ExprId, 172 pub expr: ExprId,
131} 173}
132 174
133#[derive(Debug, Clone, Eq, PartialEq)] 175#[derive(Debug, Clone, Eq, PartialEq)]
@@ -140,12 +182,118 @@ pub enum Statement {
140 Expr(ExprId), 182 Expr(ExprId),
141} 183}
142 184
185impl Expr {
186 pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) {
187 match self {
188 Expr::Missing => {}
189 Expr::Path(_) => {}
190 Expr::If {
191 condition,
192 then_branch,
193 else_branch,
194 } => {
195 f(*condition);
196 f(*then_branch);
197 if let Some(else_branch) = else_branch {
198 f(*else_branch);
199 }
200 }
201 Expr::Block { statements, tail } => {
202 for stmt in statements {
203 match stmt {
204 Statement::Let { initializer, .. } => {
205 if let Some(expr) = initializer {
206 f(*expr);
207 }
208 }
209 Statement::Expr(e) => f(*e),
210 }
211 }
212 if let Some(expr) = tail {
213 f(*expr);
214 }
215 }
216 Expr::Loop { body } => f(*body),
217 Expr::While { condition, body } => {
218 f(*condition);
219 f(*body);
220 }
221 Expr::For { iterable, body, .. } => {
222 f(*iterable);
223 f(*body);
224 }
225 Expr::Call { callee, args } => {
226 f(*callee);
227 for arg in args {
228 f(*arg);
229 }
230 }
231 Expr::MethodCall { receiver, args, .. } => {
232 f(*receiver);
233 for arg in args {
234 f(*arg);
235 }
236 }
237 Expr::Match { expr, arms } => {
238 f(*expr);
239 for arm in arms {
240 f(arm.expr);
241 }
242 }
243 Expr::Continue => {}
244 Expr::Break { expr } | Expr::Return { expr } => {
245 if let Some(expr) = expr {
246 f(*expr);
247 }
248 }
249 Expr::StructLit { fields, spread, .. } => {
250 for field in fields {
251 f(field.expr);
252 }
253 if let Some(expr) = spread {
254 f(*expr);
255 }
256 }
257 Expr::Lambda { body, .. } => {
258 f(*body);
259 }
260 Expr::Field { expr, .. }
261 | Expr::Try { expr }
262 | Expr::Cast { expr, .. }
263 | Expr::Ref { expr, .. }
264 | Expr::UnaryOp { expr, .. } => {
265 f(*expr);
266 }
267 }
268 }
269}
270
143#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 271#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
144pub struct PatId(RawId); 272pub struct PatId(RawId);
145impl_arena_id!(PatId); 273impl_arena_id!(PatId);
146 274
147#[derive(Debug, Clone, Eq, PartialEq)] 275#[derive(Debug, Clone, Eq, PartialEq)]
148pub struct Pat; 276pub enum Pat {
277 Missing,
278 Bind {
279 name: Name,
280 },
281 TupleStruct {
282 path: Option<Path>,
283 args: Vec<PatId>,
284 },
285}
286
287impl Pat {
288 pub fn walk_child_pats(&self, f: impl FnMut(PatId)) {
289 match self {
290 Pat::Missing | Pat::Bind { .. } => {}
291 Pat::TupleStruct { args, .. } => {
292 args.iter().map(|pat| *pat).for_each(f);
293 }
294 }
295 }
296}
149 297
150// Queries 298// Queries
151 299
@@ -163,6 +311,17 @@ struct ExprCollector {
163} 311}
164 312
165impl ExprCollector { 313impl ExprCollector {
314 fn new() -> Self {
315 ExprCollector {
316 exprs: Arena::default(),
317 pats: Arena::default(),
318 expr_syntax_mapping: FxHashMap::default(),
319 expr_syntax_mapping_back: FxHashMap::default(),
320 pat_syntax_mapping: FxHashMap::default(),
321 pat_syntax_mapping_back: FxHashMap::default(),
322 }
323 }
324
166 fn alloc_expr(&mut self, expr: Expr, syntax_ptr: LocalSyntaxPtr) -> ExprId { 325 fn alloc_expr(&mut self, expr: Expr, syntax_ptr: LocalSyntaxPtr) -> ExprId {
167 let id = self.exprs.alloc(expr); 326 let id = self.exprs.alloc(expr);
168 self.expr_syntax_mapping.insert(syntax_ptr, id); 327 self.expr_syntax_mapping.insert(syntax_ptr, id);
@@ -177,30 +336,63 @@ impl ExprCollector {
177 id 336 id
178 } 337 }
179 338
339 fn empty_block(&mut self) -> ExprId {
340 let block = Expr::Block {
341 statements: Vec::new(),
342 tail: None,
343 };
344 self.exprs.alloc(block)
345 }
346
180 fn collect_expr(&mut self, expr: ast::Expr) -> ExprId { 347 fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
181 let syntax_ptr = LocalSyntaxPtr::new(expr.syntax()); 348 let syntax_ptr = LocalSyntaxPtr::new(expr.syntax());
182 match expr { 349 match expr {
183 ast::Expr::IfExpr(e) => { 350 ast::Expr::IfExpr(e) => {
184 let condition = if let Some(condition) = e.condition() { 351 if let Some(pat) = e.condition().and_then(|c| c.pat()) {
185 if condition.pat().is_none() { 352 // if let -- desugar to match
353 let pat = self.collect_pat(pat);
354 let match_expr =
355 self.collect_expr_opt(e.condition().expect("checked above").expr());
356 let then_branch = self.collect_block_opt(e.then_branch());
357 let else_branch = e
358 .else_branch()
359 .map(|e| self.collect_block(e))
360 .unwrap_or_else(|| self.empty_block());
361 let placeholder_pat = self.pats.alloc(Pat::Missing);
362 let arms = vec![
363 MatchArm {
364 pats: vec![pat],
365 expr: then_branch,
366 },
367 MatchArm {
368 pats: vec![placeholder_pat],
369 expr: else_branch,
370 },
371 ];
372 self.alloc_expr(
373 Expr::Match {
374 expr: match_expr,
375 arms,
376 },
377 syntax_ptr,
378 )
379 } else {
380 let condition = if let Some(condition) = e.condition() {
186 self.collect_expr_opt(condition.expr()) 381 self.collect_expr_opt(condition.expr())
187 } else { 382 } else {
188 // TODO handle if let 383 self.exprs.alloc(Expr::Missing)
189 return self.alloc_expr(Expr::Missing, syntax_ptr); 384 };
190 } 385 let then_branch = self.collect_block_opt(e.then_branch());
191 } else { 386 let else_branch = e.else_branch().map(|e| self.collect_block(e));
192 self.exprs.alloc(Expr::Missing) 387 self.alloc_expr(
193 }; 388 Expr::If {
194 let then_branch = self.collect_block_opt(e.then_branch()); 389 condition,
195 let else_branch = e.else_branch().map(|e| self.collect_block(e)); 390 then_branch,
196 self.alloc_expr( 391 else_branch,
197 Expr::If { 392 },
198 condition, 393 syntax_ptr,
199 then_branch, 394 )
200 else_branch, 395 }
201 },
202 syntax_ptr,
203 )
204 } 396 }
205 ast::Expr::BlockExpr(e) => self.collect_block_opt(e.block()), 397 ast::Expr::BlockExpr(e) => self.collect_block_opt(e.block()),
206 ast::Expr::LoopExpr(e) => { 398 ast::Expr::LoopExpr(e) => {
@@ -368,18 +560,30 @@ impl ExprCollector {
368 let op = e.op(); 560 let op = e.op();
369 self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr) 561 self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr)
370 } 562 }
371 563 ast::Expr::LambdaExpr(e) => {
372 // We should never get to these because they're handled in MatchExpr resp. StructLit: 564 let mut args = Vec::new();
373 ast::Expr::MatchArmList(_) | ast::Expr::MatchArm(_) | ast::Expr::MatchGuard(_) => { 565 let mut arg_types = Vec::new();
374 panic!("collect_expr called on {:?}", expr) 566 if let Some(pl) = e.param_list() {
375 } 567 for param in pl.params() {
376 ast::Expr::NamedFieldList(_) | ast::Expr::NamedField(_) => { 568 let pat = self.collect_pat_opt(param.pat());
377 panic!("collect_expr called on {:?}", expr) 569 let type_ref = param.type_ref().map(TypeRef::from_ast);
570 args.push(pat);
571 arg_types.push(type_ref);
572 }
573 }
574 let body = self.collect_expr_opt(e.body());
575 self.alloc_expr(
576 Expr::Lambda {
577 args,
578 arg_types,
579 body,
580 },
581 syntax_ptr,
582 )
378 } 583 }
379 584
380 // TODO implement HIR for these: 585 // TODO implement HIR for these:
381 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 586 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
382 ast::Expr::LambdaExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
383 ast::Expr::IndexExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 587 ast::Expr::IndexExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
384 ast::Expr::TupleExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 588 ast::Expr::TupleExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
385 ast::Expr::ArrayExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 589 ast::Expr::ArrayExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
@@ -431,16 +635,31 @@ impl ExprCollector {
431 635
432 fn collect_pat(&mut self, pat: ast::Pat) -> PatId { 636 fn collect_pat(&mut self, pat: ast::Pat) -> PatId {
433 let syntax_ptr = LocalSyntaxPtr::new(pat.syntax()); 637 let syntax_ptr = LocalSyntaxPtr::new(pat.syntax());
434 // TODO 638 match pat {
435 self.alloc_pat(Pat, syntax_ptr) 639 ast::Pat::BindPat(bp) => {
640 let name = bp
641 .name()
642 .map(|nr| nr.as_name())
643 .unwrap_or_else(Name::missing);
644 self.alloc_pat(Pat::Bind { name }, syntax_ptr)
645 }
646 ast::Pat::TupleStructPat(p) => {
647 let path = p.path().and_then(Path::from_ast);
648 let args = p.args().map(|p| self.collect_pat(p)).collect();
649 self.alloc_pat(Pat::TupleStruct { path, args }, syntax_ptr)
650 }
651 _ => {
652 // TODO
653 self.alloc_pat(Pat::Missing, syntax_ptr)
654 }
655 }
436 } 656 }
437 657
438 fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId { 658 fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId {
439 if let Some(pat) = pat { 659 if let Some(pat) = pat {
440 self.collect_pat(pat) 660 self.collect_pat(pat)
441 } else { 661 } else {
442 // TODO 662 self.pats.alloc(Pat::Missing)
443 self.pats.alloc(Pat)
444 } 663 }
445 } 664 }
446 665
@@ -461,47 +680,61 @@ impl ExprCollector {
461 } 680 }
462} 681}
463 682
683pub(crate) fn collect_fn_body_syntax(node: ast::FnDef) -> BodySyntaxMapping {
684 let mut collector = ExprCollector::new();
685
686 let args = if let Some(param_list) = node.param_list() {
687 let mut args = Vec::new();
688
689 if let Some(self_param) = param_list.self_param() {
690 let self_param = LocalSyntaxPtr::new(
691 self_param
692 .self_kw()
693 .expect("self param without self keyword")
694 .syntax(),
695 );
696 let arg = collector.alloc_pat(
697 Pat::Bind {
698 name: Name::self_param(),
699 },
700 self_param,
701 );
702 args.push(arg);
703 }
704
705 for param in param_list.params() {
706 let pat = if let Some(pat) = param.pat() {
707 pat
708 } else {
709 continue;
710 };
711 args.push(collector.collect_pat(pat));
712 }
713 args
714 } else {
715 Vec::new()
716 };
717
718 let body = collector.collect_block_opt(node.body());
719 collector.into_body_syntax_mapping(args, body)
720}
721
464pub(crate) fn body_syntax_mapping( 722pub(crate) fn body_syntax_mapping(
465 db: &impl HirDatabase, 723 db: &impl HirDatabase,
466 def_id: DefId, 724 def_id: DefId,
467) -> Cancelable<Arc<BodySyntaxMapping>> { 725) -> Cancelable<Arc<BodySyntaxMapping>> {
468 let def = def_id.resolve(db)?; 726 let def = def_id.resolve(db)?;
469 let mut collector = ExprCollector {
470 exprs: Arena::default(),
471 pats: Arena::default(),
472 expr_syntax_mapping: FxHashMap::default(),
473 expr_syntax_mapping_back: FxHashMap::default(),
474 pat_syntax_mapping: FxHashMap::default(),
475 pat_syntax_mapping_back: FxHashMap::default(),
476 };
477 727
478 let (body, args) = match def { 728 let body_syntax_mapping = match def {
479 Def::Function(f) => { 729 Def::Function(f) => {
480 let node = f.syntax(db); 730 let node = f.syntax(db);
481 let node = node.borrowed(); 731 let node = node.borrowed();
482 732
483 let args = if let Some(param_list) = node.param_list() { 733 collect_fn_body_syntax(node)
484 let mut args = Vec::new();
485 // TODO self param
486 for param in param_list.params() {
487 let pat = if let Some(pat) = param.pat() {
488 pat
489 } else {
490 continue;
491 };
492 args.push(collector.collect_pat(pat));
493 }
494 args
495 } else {
496 Vec::new()
497 };
498
499 let body = collector.collect_block_opt(node.body());
500 (body, args)
501 } 734 }
502 // TODO: consts, etc. 735 // TODO: consts, etc.
503 _ => panic!("Trying to get body for item type without body"), 736 _ => panic!("Trying to get body for item type without body"),
504 }; 737 };
505 738
506 Ok(Arc::new(collector.into_body_syntax_mapping(args, body))) 739 Ok(Arc::new(body_syntax_mapping))
507} 740}