diff options
author | Florian Diebold <[email protected]> | 2019-01-05 21:37:59 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-01-05 23:29:36 +0000 |
commit | 8e3e5ab2c81f238ea4e731f55eac79b74d9d84c3 (patch) | |
tree | e0388878b4d94ae71fbf82d3e3163c49c8e69c16 /crates/ra_hir | |
parent | 136aba1cf32646278c4034541ee415f656f8bb5e (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')
-rw-r--r-- | crates/ra_hir/src/db.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/expr.rs | 363 | ||||
-rw-r--r-- | crates/ra_hir/src/function.rs | 21 | ||||
-rw-r--r-- | crates/ra_hir/src/function/scope.rs | 368 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/name.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir/src/query_definitions.rs | 11 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 19 |
8 files changed, 514 insertions, 282 deletions
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 188b96872..aaf367e08 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -31,7 +31,7 @@ pub trait HirDatabase: SyntaxDatabase | |||
31 | use fn crate::macros::expand_macro_invocation; | 31 | use fn crate::macros::expand_macro_invocation; |
32 | } | 32 | } |
33 | 33 | ||
34 | fn fn_scopes(def_id: DefId) -> Arc<FnScopes> { | 34 | fn fn_scopes(def_id: DefId) -> Cancelable<Arc<FnScopes>> { |
35 | type FnScopesQuery; | 35 | type FnScopesQuery; |
36 | use fn query_definitions::fn_scopes; | 36 | use fn query_definitions::fn_scopes; |
37 | } | 37 | } |
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 | ||
5 | use ra_arena::{Arena, RawId, impl_arena_id}; | 5 | use ra_arena::{Arena, RawId, impl_arena_id}; |
6 | use ra_db::{LocalSyntaxPtr, Cancelable}; | 6 | use ra_db::{LocalSyntaxPtr, Cancelable}; |
7 | use ra_syntax::ast::{self, AstNode, LoopBodyOwner, ArgListOwner}; | 7 | use ra_syntax::ast::{self, AstNode, LoopBodyOwner, ArgListOwner, NameOwner}; |
8 | 8 | ||
9 | use crate::{Path, type_ref::{Mutability, TypeRef}, Name, HirDatabase, DefId, Def, name::AsName}; | 9 | use 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 | ||
46 | impl 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 | |||
64 | impl 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)] |
47 | pub enum Expr { | 84 | pub 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 | ||
118 | pub type UnaryOp = ast::PrefixOp; | 160 | pub type UnaryOp = ast::PrefixOp; |
119 | 161 | ||
120 | #[derive(Debug, Clone, Eq, PartialEq)] | 162 | #[derive(Debug, Clone, Eq, PartialEq)] |
121 | pub struct MatchArm { | 163 | pub 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)] |
128 | pub struct StructLitField { | 170 | pub 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 | ||
185 | impl 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)] |
144 | pub struct PatId(RawId); | 272 | pub struct PatId(RawId); |
145 | impl_arena_id!(PatId); | 273 | impl_arena_id!(PatId); |
146 | 274 | ||
147 | #[derive(Debug, Clone, Eq, PartialEq)] | 275 | #[derive(Debug, Clone, Eq, PartialEq)] |
148 | pub struct Pat; | 276 | pub enum Pat { |
277 | Missing, | ||
278 | Bind { | ||
279 | name: Name, | ||
280 | }, | ||
281 | TupleStruct { | ||
282 | path: Option<Path>, | ||
283 | args: Vec<PatId>, | ||
284 | }, | ||
285 | } | ||
286 | |||
287 | impl 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 | ||
165 | impl ExprCollector { | 313 | impl 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 | ||
683 | pub(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 | |||
464 | pub(crate) fn body_syntax_mapping( | 722 | pub(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 | } |
diff --git a/crates/ra_hir/src/function.rs b/crates/ra_hir/src/function.rs index 75ef308ae..4dbdf81d8 100644 --- a/crates/ra_hir/src/function.rs +++ b/crates/ra_hir/src/function.rs | |||
@@ -11,9 +11,9 @@ use ra_syntax::{ | |||
11 | ast::{self, AstNode, DocCommentsOwner, NameOwner}, | 11 | ast::{self, AstNode, DocCommentsOwner, NameOwner}, |
12 | }; | 12 | }; |
13 | 13 | ||
14 | use crate::{DefId, DefKind, HirDatabase, ty::InferenceResult, Module, Crate, impl_block::ImplBlock}; | 14 | use crate::{DefId, DefKind, HirDatabase, ty::InferenceResult, Module, Crate, impl_block::ImplBlock, expr::{Body, BodySyntaxMapping}}; |
15 | 15 | ||
16 | pub use self::scope::FnScopes; | 16 | pub use self::scope::{FnScopes, ScopesWithSyntaxMapping}; |
17 | 17 | ||
18 | #[derive(Debug, Clone, PartialEq, Eq)] | 18 | #[derive(Debug, Clone, PartialEq, Eq)] |
19 | pub struct Function { | 19 | pub struct Function { |
@@ -36,8 +36,21 @@ impl Function { | |||
36 | ast::FnDef::cast(syntax.borrowed()).unwrap().owned() | 36 | ast::FnDef::cast(syntax.borrowed()).unwrap().owned() |
37 | } | 37 | } |
38 | 38 | ||
39 | pub fn scopes(&self, db: &impl HirDatabase) -> Arc<FnScopes> { | 39 | pub fn body(&self, db: &impl HirDatabase) -> Cancelable<Arc<Body>> { |
40 | db.fn_scopes(self.def_id) | 40 | db.body_hir(self.def_id) |
41 | } | ||
42 | |||
43 | pub fn body_syntax_mapping(&self, db: &impl HirDatabase) -> Cancelable<Arc<BodySyntaxMapping>> { | ||
44 | db.body_syntax_mapping(self.def_id) | ||
45 | } | ||
46 | |||
47 | pub fn scopes(&self, db: &impl HirDatabase) -> Cancelable<ScopesWithSyntaxMapping> { | ||
48 | let scopes = db.fn_scopes(self.def_id)?; | ||
49 | let syntax_mapping = db.body_syntax_mapping(self.def_id)?; | ||
50 | Ok(ScopesWithSyntaxMapping { | ||
51 | scopes, | ||
52 | syntax_mapping, | ||
53 | }) | ||
41 | } | 54 | } |
42 | 55 | ||
43 | pub fn signature_info(&self, db: &impl HirDatabase) -> Option<FnSignatureInfo> { | 56 | pub fn signature_info(&self, db: &impl HirDatabase) -> Option<FnSignatureInfo> { |
diff --git a/crates/ra_hir/src/function/scope.rs b/crates/ra_hir/src/function/scope.rs index 42bfe4f32..0607a99cb 100644 --- a/crates/ra_hir/src/function/scope.rs +++ b/crates/ra_hir/src/function/scope.rs | |||
@@ -1,14 +1,16 @@ | |||
1 | use std::sync::Arc; | ||
2 | |||
1 | use rustc_hash::{FxHashMap, FxHashSet}; | 3 | use rustc_hash::{FxHashMap, FxHashSet}; |
2 | 4 | ||
3 | use ra_syntax::{ | 5 | use ra_syntax::{ |
4 | AstNode, SyntaxNodeRef, TextUnit, TextRange, | 6 | AstNode, SyntaxNodeRef, TextUnit, TextRange, |
5 | algo::generate, | 7 | algo::generate, |
6 | ast::{self, ArgListOwner, LoopBodyOwner, NameOwner}, | 8 | ast, |
7 | }; | 9 | }; |
8 | use ra_arena::{Arena, RawId, impl_arena_id}; | 10 | use ra_arena::{Arena, RawId, impl_arena_id}; |
9 | use ra_db::LocalSyntaxPtr; | 11 | use ra_db::LocalSyntaxPtr; |
10 | 12 | ||
11 | use crate::{Name, AsName}; | 13 | use crate::{Name, AsName, expr::{PatId, ExprId, Pat, Expr, Body, Statement, BodySyntaxMapping}}; |
12 | 14 | ||
13 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | 15 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
14 | pub struct ScopeId(RawId); | 16 | pub struct ScopeId(RawId); |
@@ -16,15 +18,15 @@ impl_arena_id!(ScopeId); | |||
16 | 18 | ||
17 | #[derive(Debug, PartialEq, Eq)] | 19 | #[derive(Debug, PartialEq, Eq)] |
18 | pub struct FnScopes { | 20 | pub struct FnScopes { |
19 | pub self_param: Option<LocalSyntaxPtr>, | 21 | body: Arc<Body>, |
20 | scopes: Arena<ScopeId, ScopeData>, | 22 | scopes: Arena<ScopeId, ScopeData>, |
21 | scope_for: FxHashMap<LocalSyntaxPtr, ScopeId>, | 23 | scope_for: FxHashMap<ExprId, ScopeId>, |
22 | } | 24 | } |
23 | 25 | ||
24 | #[derive(Debug, PartialEq, Eq)] | 26 | #[derive(Debug, PartialEq, Eq)] |
25 | pub struct ScopeEntry { | 27 | pub struct ScopeEntry { |
26 | name: Name, | 28 | name: Name, |
27 | ptr: LocalSyntaxPtr, | 29 | pat: PatId, |
28 | } | 30 | } |
29 | 31 | ||
30 | #[derive(Debug, PartialEq, Eq)] | 32 | #[derive(Debug, PartialEq, Eq)] |
@@ -34,28 +36,101 @@ pub struct ScopeData { | |||
34 | } | 36 | } |
35 | 37 | ||
36 | impl FnScopes { | 38 | impl FnScopes { |
37 | pub(crate) fn new(fn_def: ast::FnDef) -> FnScopes { | 39 | pub(crate) fn new(body: Arc<Body>) -> FnScopes { |
38 | let mut scopes = FnScopes { | 40 | let mut scopes = FnScopes { |
39 | self_param: fn_def | 41 | body: body.clone(), |
40 | .param_list() | ||
41 | .and_then(|it| it.self_param()) | ||
42 | .map(|it| LocalSyntaxPtr::new(it.syntax())), | ||
43 | scopes: Arena::default(), | 42 | scopes: Arena::default(), |
44 | scope_for: FxHashMap::default(), | 43 | scope_for: FxHashMap::default(), |
45 | }; | 44 | }; |
46 | let root = scopes.root_scope(); | 45 | let root = scopes.root_scope(); |
47 | scopes.add_params_bindings(root, fn_def.param_list()); | 46 | scopes.add_params_bindings(root, body.args()); |
48 | if let Some(body) = fn_def.body() { | 47 | compute_expr_scopes(body.body_expr(), &body, &mut scopes, root); |
49 | compute_block_scopes(body, &mut scopes, root) | ||
50 | } | ||
51 | scopes | 48 | scopes |
52 | } | 49 | } |
53 | pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { | 50 | pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { |
54 | &self.scopes[scope].entries | 51 | &self.scopes[scope].entries |
55 | } | 52 | } |
53 | pub fn scope_chain_for<'a>(&'a self, expr: ExprId) -> impl Iterator<Item = ScopeId> + 'a { | ||
54 | generate(self.scope_for(expr), move |&scope| { | ||
55 | self.scopes[scope].parent | ||
56 | }) | ||
57 | } | ||
58 | |||
59 | pub fn resolve_local_name<'a>( | ||
60 | &'a self, | ||
61 | context_expr: ExprId, | ||
62 | name: Name, | ||
63 | ) -> Option<&'a ScopeEntry> { | ||
64 | let mut shadowed = FxHashSet::default(); | ||
65 | let ret = self | ||
66 | .scope_chain_for(context_expr) | ||
67 | .flat_map(|scope| self.entries(scope).iter()) | ||
68 | .filter(|entry| shadowed.insert(entry.name())) | ||
69 | .filter(|entry| entry.name() == &name) | ||
70 | .nth(0); | ||
71 | ret | ||
72 | } | ||
73 | |||
74 | fn root_scope(&mut self) -> ScopeId { | ||
75 | self.scopes.alloc(ScopeData { | ||
76 | parent: None, | ||
77 | entries: vec![], | ||
78 | }) | ||
79 | } | ||
80 | fn new_scope(&mut self, parent: ScopeId) -> ScopeId { | ||
81 | self.scopes.alloc(ScopeData { | ||
82 | parent: Some(parent), | ||
83 | entries: vec![], | ||
84 | }) | ||
85 | } | ||
86 | fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { | ||
87 | match body.pat(pat) { | ||
88 | Pat::Bind { name } => self.scopes[scope].entries.push(ScopeEntry { | ||
89 | name: name.clone(), | ||
90 | pat, | ||
91 | }), | ||
92 | p => p.walk_child_pats(|pat| self.add_bindings(body, scope, pat)), | ||
93 | } | ||
94 | } | ||
95 | fn add_params_bindings(&mut self, scope: ScopeId, params: &[PatId]) { | ||
96 | let body = Arc::clone(&self.body); | ||
97 | params | ||
98 | .into_iter() | ||
99 | .for_each(|it| self.add_bindings(&body, scope, *it)); | ||
100 | } | ||
101 | fn set_scope(&mut self, node: ExprId, scope: ScopeId) { | ||
102 | self.scope_for.insert(node, scope); | ||
103 | } | ||
104 | fn scope_for(&self, expr: ExprId) -> Option<ScopeId> { | ||
105 | self.scope_for.get(&expr).map(|&scope| scope) | ||
106 | } | ||
107 | } | ||
108 | |||
109 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
110 | pub struct ScopesWithSyntaxMapping { | ||
111 | pub syntax_mapping: Arc<BodySyntaxMapping>, | ||
112 | pub scopes: Arc<FnScopes>, | ||
113 | } | ||
114 | |||
115 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
116 | pub struct ScopeEntryWithSyntax { | ||
117 | name: Name, | ||
118 | ptr: LocalSyntaxPtr, | ||
119 | } | ||
120 | |||
121 | impl ScopeEntryWithSyntax { | ||
122 | pub fn name(&self) -> &Name { | ||
123 | &self.name | ||
124 | } | ||
125 | pub fn ptr(&self) -> LocalSyntaxPtr { | ||
126 | self.ptr | ||
127 | } | ||
128 | } | ||
129 | |||
130 | impl ScopesWithSyntaxMapping { | ||
56 | pub fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item = ScopeId> + 'a { | 131 | pub fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item = ScopeId> + 'a { |
57 | generate(self.scope_for(node), move |&scope| { | 132 | generate(self.scope_for(node), move |&scope| { |
58 | self.scopes[scope].parent | 133 | self.scopes.scopes[scope].parent |
59 | }) | 134 | }) |
60 | } | 135 | } |
61 | pub fn scope_chain_for_offset<'a>( | 136 | pub fn scope_chain_for_offset<'a>( |
@@ -63,26 +138,30 @@ impl FnScopes { | |||
63 | offset: TextUnit, | 138 | offset: TextUnit, |
64 | ) -> impl Iterator<Item = ScopeId> + 'a { | 139 | ) -> impl Iterator<Item = ScopeId> + 'a { |
65 | let scope = self | 140 | let scope = self |
141 | .scopes | ||
66 | .scope_for | 142 | .scope_for |
67 | .iter() | 143 | .iter() |
68 | // find containin scope | 144 | .filter_map(|(id, scope)| Some((self.syntax_mapping.expr_syntax(*id)?, scope))) |
145 | // find containing scope | ||
69 | .min_by_key(|(ptr, _scope)| { | 146 | .min_by_key(|(ptr, _scope)| { |
70 | ( | 147 | ( |
71 | !(ptr.range().start() <= offset && offset <= ptr.range().end()), | 148 | !(ptr.range().start() <= offset && offset <= ptr.range().end()), |
72 | ptr.range().len(), | 149 | ptr.range().len(), |
73 | ) | 150 | ) |
74 | }) | 151 | }) |
75 | .map(|(ptr, scope)| self.adjust(*ptr, *scope, offset)); | 152 | .map(|(ptr, scope)| self.adjust(ptr, *scope, offset)); |
76 | 153 | ||
77 | generate(scope, move |&scope| self.scopes[scope].parent) | 154 | generate(scope, move |&scope| self.scopes.scopes[scope].parent) |
78 | } | 155 | } |
79 | // XXX: during completion, cursor might be outside of any particular | 156 | // XXX: during completion, cursor might be outside of any particular |
80 | // expression. Try to figure out the correct scope... | 157 | // expression. Try to figure out the correct scope... |
81 | fn adjust(&self, ptr: LocalSyntaxPtr, original_scope: ScopeId, offset: TextUnit) -> ScopeId { | 158 | fn adjust(&self, ptr: LocalSyntaxPtr, original_scope: ScopeId, offset: TextUnit) -> ScopeId { |
82 | let r = ptr.range(); | 159 | let r = ptr.range(); |
83 | let child_scopes = self | 160 | let child_scopes = self |
161 | .scopes | ||
84 | .scope_for | 162 | .scope_for |
85 | .iter() | 163 | .iter() |
164 | .filter_map(|(id, scope)| Some((self.syntax_mapping.expr_syntax(*id)?, scope))) | ||
86 | .map(|(ptr, scope)| (ptr.range(), scope)) | 165 | .map(|(ptr, scope)| (ptr.range(), scope)) |
87 | .filter(|(range, _)| range.start() <= offset && range.is_subrange(&r) && *range != r); | 166 | .filter(|(range, _)| range.start() <= offset && range.is_subrange(&r) && *range != r); |
88 | 167 | ||
@@ -100,22 +179,27 @@ impl FnScopes { | |||
100 | .unwrap_or(original_scope) | 179 | .unwrap_or(original_scope) |
101 | } | 180 | } |
102 | 181 | ||
103 | pub fn resolve_local_name<'a>(&'a self, name_ref: ast::NameRef) -> Option<&'a ScopeEntry> { | 182 | pub fn resolve_local_name(&self, name_ref: ast::NameRef) -> Option<ScopeEntryWithSyntax> { |
104 | let mut shadowed = FxHashSet::default(); | 183 | let mut shadowed = FxHashSet::default(); |
105 | let name = name_ref.as_name(); | 184 | let name = name_ref.as_name(); |
106 | let ret = self | 185 | let ret = self |
107 | .scope_chain(name_ref.syntax()) | 186 | .scope_chain(name_ref.syntax()) |
108 | .flat_map(|scope| self.entries(scope).iter()) | 187 | .flat_map(|scope| self.scopes.entries(scope).iter()) |
109 | .filter(|entry| shadowed.insert(entry.name())) | 188 | .filter(|entry| shadowed.insert(entry.name())) |
110 | .filter(|entry| entry.name() == &name) | 189 | .filter(|entry| entry.name() == &name) |
111 | .nth(0); | 190 | .nth(0); |
112 | ret | 191 | ret.and_then(|entry| { |
192 | Some(ScopeEntryWithSyntax { | ||
193 | name: entry.name().clone(), | ||
194 | ptr: self.syntax_mapping.pat_syntax(entry.pat())?, | ||
195 | }) | ||
196 | }) | ||
113 | } | 197 | } |
114 | 198 | ||
115 | pub fn find_all_refs(&self, pat: ast::BindPat) -> Vec<ReferenceDescriptor> { | 199 | pub fn find_all_refs(&self, pat: ast::BindPat) -> Vec<ReferenceDescriptor> { |
116 | let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); | 200 | let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); |
117 | let name_ptr = LocalSyntaxPtr::new(pat.syntax()); | 201 | let name_ptr = LocalSyntaxPtr::new(pat.syntax()); |
118 | let refs: Vec<_> = fn_def | 202 | fn_def |
119 | .syntax() | 203 | .syntax() |
120 | .descendants() | 204 | .descendants() |
121 | .filter_map(ast::NameRef::cast) | 205 | .filter_map(ast::NameRef::cast) |
@@ -127,203 +211,95 @@ impl FnScopes { | |||
127 | name: name_ref.syntax().text().to_string(), | 211 | name: name_ref.syntax().text().to_string(), |
128 | range: name_ref.syntax().range(), | 212 | range: name_ref.syntax().range(), |
129 | }) | 213 | }) |
130 | .collect(); | 214 | .collect() |
131 | |||
132 | refs | ||
133 | } | 215 | } |
134 | 216 | ||
135 | fn root_scope(&mut self) -> ScopeId { | ||
136 | self.scopes.alloc(ScopeData { | ||
137 | parent: None, | ||
138 | entries: vec![], | ||
139 | }) | ||
140 | } | ||
141 | fn new_scope(&mut self, parent: ScopeId) -> ScopeId { | ||
142 | self.scopes.alloc(ScopeData { | ||
143 | parent: Some(parent), | ||
144 | entries: vec![], | ||
145 | }) | ||
146 | } | ||
147 | fn add_bindings(&mut self, scope: ScopeId, pat: ast::Pat) { | ||
148 | let entries = pat | ||
149 | .syntax() | ||
150 | .descendants() | ||
151 | .filter_map(ast::BindPat::cast) | ||
152 | .filter_map(ScopeEntry::new); | ||
153 | self.scopes[scope].entries.extend(entries); | ||
154 | } | ||
155 | fn add_params_bindings(&mut self, scope: ScopeId, params: Option<ast::ParamList>) { | ||
156 | params | ||
157 | .into_iter() | ||
158 | .flat_map(|it| it.params()) | ||
159 | .filter_map(|it| it.pat()) | ||
160 | .for_each(|it| self.add_bindings(scope, it)); | ||
161 | } | ||
162 | fn set_scope(&mut self, node: SyntaxNodeRef, scope: ScopeId) { | ||
163 | self.scope_for.insert(LocalSyntaxPtr::new(node), scope); | ||
164 | } | ||
165 | fn scope_for(&self, node: SyntaxNodeRef) -> Option<ScopeId> { | 217 | fn scope_for(&self, node: SyntaxNodeRef) -> Option<ScopeId> { |
166 | node.ancestors() | 218 | node.ancestors() |
167 | .map(LocalSyntaxPtr::new) | 219 | .map(LocalSyntaxPtr::new) |
168 | .filter_map(|it| self.scope_for.get(&it).map(|&scope| scope)) | 220 | .filter_map(|ptr| self.syntax_mapping.syntax_expr(ptr)) |
221 | .filter_map(|it| self.scopes.scope_for(it)) | ||
169 | .next() | 222 | .next() |
170 | } | 223 | } |
171 | } | 224 | } |
172 | 225 | ||
173 | impl ScopeEntry { | 226 | impl ScopeEntry { |
174 | fn new(pat: ast::BindPat) -> Option<ScopeEntry> { | ||
175 | let name = pat.name()?.as_name(); | ||
176 | let res = ScopeEntry { | ||
177 | name, | ||
178 | ptr: LocalSyntaxPtr::new(pat.syntax()), | ||
179 | }; | ||
180 | Some(res) | ||
181 | } | ||
182 | pub fn name(&self) -> &Name { | 227 | pub fn name(&self) -> &Name { |
183 | &self.name | 228 | &self.name |
184 | } | 229 | } |
185 | pub fn ptr(&self) -> LocalSyntaxPtr { | 230 | pub fn pat(&self) -> PatId { |
186 | self.ptr | 231 | self.pat |
187 | } | 232 | } |
188 | } | 233 | } |
189 | 234 | ||
190 | fn compute_block_scopes(block: ast::Block, scopes: &mut FnScopes, mut scope: ScopeId) { | 235 | fn compute_block_scopes( |
191 | // A hack for completion :( | 236 | statements: &[Statement], |
192 | scopes.set_scope(block.syntax(), scope); | 237 | tail: Option<ExprId>, |
193 | for stmt in block.statements() { | 238 | body: &Body, |
239 | scopes: &mut FnScopes, | ||
240 | mut scope: ScopeId, | ||
241 | ) { | ||
242 | for stmt in statements { | ||
194 | match stmt { | 243 | match stmt { |
195 | ast::Stmt::LetStmt(stmt) => { | 244 | Statement::Let { |
196 | if let Some(expr) = stmt.initializer() { | 245 | pat, initializer, .. |
197 | scopes.set_scope(expr.syntax(), scope); | 246 | } => { |
198 | compute_expr_scopes(expr, scopes, scope); | 247 | if let Some(expr) = initializer { |
248 | scopes.set_scope(*expr, scope); | ||
249 | compute_expr_scopes(*expr, body, scopes, scope); | ||
199 | } | 250 | } |
200 | scope = scopes.new_scope(scope); | 251 | scope = scopes.new_scope(scope); |
201 | if let Some(pat) = stmt.pat() { | 252 | scopes.add_bindings(body, scope, *pat); |
202 | scopes.add_bindings(scope, pat); | ||
203 | } | ||
204 | } | 253 | } |
205 | ast::Stmt::ExprStmt(expr_stmt) => { | 254 | Statement::Expr(expr) => { |
206 | if let Some(expr) = expr_stmt.expr() { | 255 | scopes.set_scope(*expr, scope); |
207 | scopes.set_scope(expr.syntax(), scope); | 256 | compute_expr_scopes(*expr, body, scopes, scope); |
208 | compute_expr_scopes(expr, scopes, scope); | ||
209 | } | ||
210 | } | 257 | } |
211 | } | 258 | } |
212 | } | 259 | } |
213 | if let Some(expr) = block.expr() { | 260 | if let Some(expr) = tail { |
214 | scopes.set_scope(expr.syntax(), scope); | 261 | compute_expr_scopes(expr, body, scopes, scope); |
215 | compute_expr_scopes(expr, scopes, scope); | ||
216 | } | 262 | } |
217 | } | 263 | } |
218 | 264 | ||
219 | fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) { | 265 | fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut FnScopes, scope: ScopeId) { |
220 | match expr { | 266 | scopes.set_scope(expr, scope); |
221 | ast::Expr::IfExpr(e) => { | 267 | match body.expr(expr) { |
222 | let cond_scope = e | 268 | Expr::Block { statements, tail } => { |
223 | .condition() | 269 | compute_block_scopes(&statements, *tail, body, scopes, scope); |
224 | .and_then(|cond| compute_cond_scopes(cond, scopes, scope)); | ||
225 | if let Some(block) = e.then_branch() { | ||
226 | compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope)); | ||
227 | } | ||
228 | if let Some(block) = e.else_branch() { | ||
229 | compute_block_scopes(block, scopes, scope); | ||
230 | } | ||
231 | } | ||
232 | ast::Expr::BlockExpr(e) => { | ||
233 | if let Some(block) = e.block() { | ||
234 | compute_block_scopes(block, scopes, scope); | ||
235 | } | ||
236 | } | ||
237 | ast::Expr::LoopExpr(e) => { | ||
238 | if let Some(block) = e.loop_body() { | ||
239 | compute_block_scopes(block, scopes, scope); | ||
240 | } | ||
241 | } | ||
242 | ast::Expr::WhileExpr(e) => { | ||
243 | let cond_scope = e | ||
244 | .condition() | ||
245 | .and_then(|cond| compute_cond_scopes(cond, scopes, scope)); | ||
246 | if let Some(block) = e.loop_body() { | ||
247 | compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope)); | ||
248 | } | ||
249 | } | 270 | } |
250 | ast::Expr::ForExpr(e) => { | 271 | Expr::For { |
251 | if let Some(expr) = e.iterable() { | 272 | iterable, |
252 | compute_expr_scopes(expr, scopes, scope); | 273 | pat, |
253 | } | 274 | body: body_expr, |
254 | let mut scope = scope; | 275 | } => { |
255 | if let Some(pat) = e.pat() { | 276 | compute_expr_scopes(*iterable, body, scopes, scope); |
256 | scope = scopes.new_scope(scope); | ||
257 | scopes.add_bindings(scope, pat); | ||
258 | } | ||
259 | if let Some(block) = e.loop_body() { | ||
260 | compute_block_scopes(block, scopes, scope); | ||
261 | } | ||
262 | } | ||
263 | ast::Expr::LambdaExpr(e) => { | ||
264 | let scope = scopes.new_scope(scope); | 277 | let scope = scopes.new_scope(scope); |
265 | scopes.add_params_bindings(scope, e.param_list()); | 278 | scopes.add_bindings(body, scope, *pat); |
266 | if let Some(body) = e.body() { | 279 | compute_expr_scopes(*body_expr, body, scopes, scope); |
267 | scopes.set_scope(body.syntax(), scope); | ||
268 | compute_expr_scopes(body, scopes, scope); | ||
269 | } | ||
270 | } | 280 | } |
271 | ast::Expr::CallExpr(e) => { | 281 | Expr::Lambda { |
272 | compute_call_scopes(e.expr(), e.arg_list(), scopes, scope); | 282 | args, |
273 | } | 283 | body: body_expr, |
274 | ast::Expr::MethodCallExpr(e) => { | 284 | .. |
275 | compute_call_scopes(e.expr(), e.arg_list(), scopes, scope); | 285 | } => { |
286 | let scope = scopes.new_scope(scope); | ||
287 | scopes.add_params_bindings(scope, &args); | ||
288 | compute_expr_scopes(*body_expr, body, scopes, scope); | ||
276 | } | 289 | } |
277 | ast::Expr::MatchExpr(e) => { | 290 | Expr::Match { expr, arms } => { |
278 | if let Some(expr) = e.expr() { | 291 | compute_expr_scopes(*expr, body, scopes, scope); |
279 | compute_expr_scopes(expr, scopes, scope); | 292 | for arm in arms { |
280 | } | ||
281 | for arm in e.match_arm_list().into_iter().flat_map(|it| it.arms()) { | ||
282 | let scope = scopes.new_scope(scope); | 293 | let scope = scopes.new_scope(scope); |
283 | for pat in arm.pats() { | 294 | for pat in &arm.pats { |
284 | scopes.add_bindings(scope, pat); | 295 | scopes.add_bindings(body, scope, *pat); |
285 | } | ||
286 | if let Some(expr) = arm.expr() { | ||
287 | compute_expr_scopes(expr, scopes, scope); | ||
288 | } | 296 | } |
297 | scopes.set_scope(arm.expr, scope); | ||
298 | compute_expr_scopes(arm.expr, body, scopes, scope); | ||
289 | } | 299 | } |
290 | } | 300 | } |
291 | _ => expr | 301 | e => e.walk_child_exprs(|e| compute_expr_scopes(e, body, scopes, scope)), |
292 | .syntax() | ||
293 | .children() | ||
294 | .filter_map(ast::Expr::cast) | ||
295 | .for_each(|expr| compute_expr_scopes(expr, scopes, scope)), | ||
296 | }; | 302 | }; |
297 | |||
298 | fn compute_call_scopes( | ||
299 | receiver: Option<ast::Expr>, | ||
300 | arg_list: Option<ast::ArgList>, | ||
301 | scopes: &mut FnScopes, | ||
302 | scope: ScopeId, | ||
303 | ) { | ||
304 | arg_list | ||
305 | .into_iter() | ||
306 | .flat_map(|it| it.args()) | ||
307 | .chain(receiver) | ||
308 | .for_each(|expr| compute_expr_scopes(expr, scopes, scope)); | ||
309 | } | ||
310 | |||
311 | fn compute_cond_scopes( | ||
312 | cond: ast::Condition, | ||
313 | scopes: &mut FnScopes, | ||
314 | scope: ScopeId, | ||
315 | ) -> Option<ScopeId> { | ||
316 | if let Some(expr) = cond.expr() { | ||
317 | compute_expr_scopes(expr, scopes, scope); | ||
318 | } | ||
319 | if let Some(pat) = cond.pat() { | ||
320 | let s = scopes.new_scope(scope); | ||
321 | scopes.add_bindings(s, pat); | ||
322 | Some(s) | ||
323 | } else { | ||
324 | None | ||
325 | } | ||
326 | } | ||
327 | } | 303 | } |
328 | 304 | ||
329 | #[derive(Debug)] | 305 | #[derive(Debug)] |
@@ -338,6 +314,8 @@ mod tests { | |||
338 | use ra_syntax::SourceFileNode; | 314 | use ra_syntax::SourceFileNode; |
339 | use test_utils::{extract_offset, assert_eq_text}; | 315 | use test_utils::{extract_offset, assert_eq_text}; |
340 | 316 | ||
317 | use crate::expr; | ||
318 | |||
341 | use super::*; | 319 | use super::*; |
342 | 320 | ||
343 | fn do_check(code: &str, expected: &[&str]) { | 321 | fn do_check(code: &str, expected: &[&str]) { |
@@ -353,15 +331,20 @@ mod tests { | |||
353 | let file = SourceFileNode::parse(&code); | 331 | let file = SourceFileNode::parse(&code); |
354 | let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); | 332 | let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); |
355 | let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); | 333 | let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); |
356 | let scopes = FnScopes::new(fn_def); | 334 | let body_hir = expr::collect_fn_body_syntax(fn_def); |
335 | let scopes = FnScopes::new(Arc::clone(body_hir.body())); | ||
336 | let scopes = ScopesWithSyntaxMapping { | ||
337 | scopes: Arc::new(scopes), | ||
338 | syntax_mapping: Arc::new(body_hir), | ||
339 | }; | ||
357 | let actual = scopes | 340 | let actual = scopes |
358 | .scope_chain(marker.syntax()) | 341 | .scope_chain(marker.syntax()) |
359 | .flat_map(|scope| scopes.entries(scope)) | 342 | .flat_map(|scope| scopes.scopes.entries(scope)) |
360 | .map(|it| it.name().to_string()) | 343 | .map(|it| it.name().to_string()) |
361 | .collect::<Vec<_>>() | 344 | .collect::<Vec<_>>() |
362 | .join("\n"); | 345 | .join("\n"); |
363 | let expected = expected.join("\n"); | 346 | let expected = expected.join("\n"); |
364 | assert_eq_text!(&actual, &expected); | 347 | assert_eq_text!(&expected, &actual); |
365 | } | 348 | } |
366 | 349 | ||
367 | #[test] | 350 | #[test] |
@@ -389,7 +372,7 @@ mod tests { | |||
389 | } | 372 | } |
390 | 373 | ||
391 | #[test] | 374 | #[test] |
392 | fn test_metod_call_scope() { | 375 | fn test_method_call_scope() { |
393 | do_check( | 376 | do_check( |
394 | r" | 377 | r" |
395 | fn quux() { | 378 | fn quux() { |
@@ -445,10 +428,15 @@ mod tests { | |||
445 | let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); | 428 | let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); |
446 | let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); | 429 | let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); |
447 | 430 | ||
448 | let scopes = FnScopes::new(fn_def); | 431 | let body_hir = expr::collect_fn_body_syntax(fn_def); |
432 | let scopes = FnScopes::new(Arc::clone(body_hir.body())); | ||
433 | let scopes = ScopesWithSyntaxMapping { | ||
434 | scopes: Arc::new(scopes), | ||
435 | syntax_mapping: Arc::new(body_hir), | ||
436 | }; | ||
449 | 437 | ||
450 | let local_name_entry = scopes.resolve_local_name(name_ref).unwrap(); | 438 | let local_name_entry = scopes.resolve_local_name(name_ref).unwrap(); |
451 | let local_name = local_name_entry.ptr().resolve(&file); | 439 | let local_name = local_name_entry.ptr(); |
452 | let expected_name = | 440 | let expected_name = |
453 | find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()).unwrap(); | 441 | find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()).unwrap(); |
454 | assert_eq!(local_name.range(), expected_name.syntax().range()); | 442 | assert_eq!(local_name.range(), expected_name.syntax().range()); |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index fea9e141b..82dc287de 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -47,7 +47,7 @@ pub use self::{ | |||
47 | ids::{HirFileId, DefId, DefLoc, MacroCallId, MacroCallLoc}, | 47 | ids::{HirFileId, DefId, DefLoc, MacroCallId, MacroCallLoc}, |
48 | macros::{MacroDef, MacroInput, MacroExpansion}, | 48 | macros::{MacroDef, MacroInput, MacroExpansion}, |
49 | module::{Module, ModuleId, Problem, nameres::{ItemMap, PerNs, Namespace}, ModuleScope, Resolution}, | 49 | module::{Module, ModuleId, Problem, nameres::{ItemMap, PerNs, Namespace}, ModuleScope, Resolution}, |
50 | function::{Function, FnScopes}, | 50 | function::{Function, FnScopes, ScopesWithSyntaxMapping}, |
51 | adt::{Struct, Enum}, | 51 | adt::{Struct, Enum}, |
52 | ty::Ty, | 52 | ty::Ty, |
53 | impl_block::{ImplBlock, ImplItem}, | 53 | impl_block::{ImplBlock, ImplItem}, |
diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs index 017caf442..6f95b168f 100644 --- a/crates/ra_hir/src/name.rs +++ b/crates/ra_hir/src/name.rs | |||
@@ -31,6 +31,10 @@ impl Name { | |||
31 | Name::new("[missing name]".into()) | 31 | Name::new("[missing name]".into()) |
32 | } | 32 | } |
33 | 33 | ||
34 | pub(crate) fn self_param() -> Name { | ||
35 | Name::new("self".into()) | ||
36 | } | ||
37 | |||
34 | pub(crate) fn tuple_field_name(idx: usize) -> Name { | 38 | pub(crate) fn tuple_field_name(idx: usize) -> Name { |
35 | Name::new(idx.to_string().into()) | 39 | Name::new(idx.to_string().into()) |
36 | } | 40 | } |
@@ -51,7 +55,8 @@ impl Name { | |||
51 | "u128" => KnownName::U128, | 55 | "u128" => KnownName::U128, |
52 | "f32" => KnownName::F32, | 56 | "f32" => KnownName::F32, |
53 | "f64" => KnownName::F64, | 57 | "f64" => KnownName::F64, |
54 | "Self" => KnownName::Self_, | 58 | "Self" => KnownName::SelfType, |
59 | "self" => KnownName::SelfParam, | ||
55 | _ => return None, | 60 | _ => return None, |
56 | }; | 61 | }; |
57 | Some(name) | 62 | Some(name) |
@@ -104,5 +109,6 @@ pub(crate) enum KnownName { | |||
104 | F32, | 109 | F32, |
105 | F64, | 110 | F64, |
106 | 111 | ||
107 | Self_, | 112 | SelfType, |
113 | SelfParam, | ||
108 | } | 114 | } |
diff --git a/crates/ra_hir/src/query_definitions.rs b/crates/ra_hir/src/query_definitions.rs index a5d99beda..d9ee9d37f 100644 --- a/crates/ra_hir/src/query_definitions.rs +++ b/crates/ra_hir/src/query_definitions.rs | |||
@@ -11,7 +11,7 @@ use ra_syntax::{ | |||
11 | use ra_db::{SourceRootId, Cancelable,}; | 11 | use ra_db::{SourceRootId, Cancelable,}; |
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
14 | SourceFileItems, SourceItemId, DefKind, Function, DefId, Name, AsName, HirFileId, | 14 | SourceFileItems, SourceItemId, DefKind, DefId, Name, AsName, HirFileId, |
15 | MacroCallLoc, | 15 | MacroCallLoc, |
16 | db::HirDatabase, | 16 | db::HirDatabase, |
17 | function::FnScopes, | 17 | function::FnScopes, |
@@ -23,11 +23,10 @@ use crate::{ | |||
23 | adt::{StructData, EnumData}, | 23 | adt::{StructData, EnumData}, |
24 | }; | 24 | }; |
25 | 25 | ||
26 | pub(super) fn fn_scopes(db: &impl HirDatabase, def_id: DefId) -> Arc<FnScopes> { | 26 | pub(super) fn fn_scopes(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<FnScopes>> { |
27 | let function = Function::new(def_id); | 27 | let body = db.body_hir(def_id)?; |
28 | let syntax = function.syntax(db); | 28 | let res = FnScopes::new(body); |
29 | let res = FnScopes::new(syntax.borrowed()); | 29 | Ok(Arc::new(res)) |
30 | Arc::new(res) | ||
31 | } | 30 | } |
32 | 31 | ||
33 | pub(super) fn struct_data(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<StructData>> { | 32 | pub(super) fn struct_data(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<StructData>> { |
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index e33762e0d..8c320a705 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -31,10 +31,11 @@ use ra_syntax::{ | |||
31 | }; | 31 | }; |
32 | 32 | ||
33 | use crate::{ | 33 | use crate::{ |
34 | Def, DefId, FnScopes, Module, Function, Struct, Enum, Path, Name, AsName, ImplBlock, | 34 | Def, DefId, Module, Function, Struct, Enum, Path, Name, AsName, ImplBlock, |
35 | db::HirDatabase, | 35 | db::HirDatabase, |
36 | type_ref::{TypeRef, Mutability}, | 36 | type_ref::{TypeRef, Mutability}, |
37 | name::KnownName, | 37 | name::KnownName, |
38 | ScopesWithSyntaxMapping, | ||
38 | }; | 39 | }; |
39 | 40 | ||
40 | /// The ID of a type variable. | 41 | /// The ID of a type variable. |
@@ -305,7 +306,7 @@ impl Ty { | |||
305 | return Ok(Ty::Uint(uint_ty)); | 306 | return Ok(Ty::Uint(uint_ty)); |
306 | } else if let Some(float_ty) = primitive::FloatTy::from_name(name) { | 307 | } else if let Some(float_ty) = primitive::FloatTy::from_name(name) { |
307 | return Ok(Ty::Float(float_ty)); | 308 | return Ok(Ty::Float(float_ty)); |
308 | } else if name.as_known_name() == Some(KnownName::Self_) { | 309 | } else if name.as_known_name() == Some(KnownName::SelfType) { |
309 | return Ty::from_hir_opt(db, module, None, impl_block.map(|i| i.target_type())); | 310 | return Ty::from_hir_opt(db, module, None, impl_block.map(|i| i.target_type())); |
310 | } | 311 | } |
311 | } | 312 | } |
@@ -515,7 +516,7 @@ impl InferenceResult { | |||
515 | #[derive(Clone, Debug)] | 516 | #[derive(Clone, Debug)] |
516 | struct InferenceContext<'a, D: HirDatabase> { | 517 | struct InferenceContext<'a, D: HirDatabase> { |
517 | db: &'a D, | 518 | db: &'a D, |
518 | scopes: Arc<FnScopes>, | 519 | scopes: ScopesWithSyntaxMapping, |
519 | /// The self param for the current method, if it exists. | 520 | /// The self param for the current method, if it exists. |
520 | self_param: Option<LocalSyntaxPtr>, | 521 | self_param: Option<LocalSyntaxPtr>, |
521 | module: Module, | 522 | module: Module, |
@@ -529,7 +530,7 @@ struct InferenceContext<'a, D: HirDatabase> { | |||
529 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 530 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
530 | fn new( | 531 | fn new( |
531 | db: &'a D, | 532 | db: &'a D, |
532 | scopes: Arc<FnScopes>, | 533 | scopes: ScopesWithSyntaxMapping, |
533 | module: Module, | 534 | module: Module, |
534 | impl_block: Option<ImplBlock>, | 535 | impl_block: Option<ImplBlock>, |
535 | ) -> Self { | 536 | ) -> Self { |
@@ -826,10 +827,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
826 | self.infer_expr_opt(e.expr(), &Expectation::none())?; | 827 | self.infer_expr_opt(e.expr(), &Expectation::none())?; |
827 | Ty::Never | 828 | Ty::Never |
828 | } | 829 | } |
829 | ast::Expr::MatchArmList(_) | ast::Expr::MatchArm(_) | ast::Expr::MatchGuard(_) => { | ||
830 | // Can this even occur outside of a match expression? | ||
831 | Ty::Unknown | ||
832 | } | ||
833 | ast::Expr::StructLit(e) => { | 830 | ast::Expr::StructLit(e) => { |
834 | let (ty, def_id) = self.resolve_variant(e.path())?; | 831 | let (ty, def_id) = self.resolve_variant(e.path())?; |
835 | if let Some(nfl) = e.named_field_list() { | 832 | if let Some(nfl) = e.named_field_list() { |
@@ -845,10 +842,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
845 | } | 842 | } |
846 | ty | 843 | ty |
847 | } | 844 | } |
848 | ast::Expr::NamedFieldList(_) | ast::Expr::NamedField(_) => { | ||
849 | // Can this even occur outside of a struct literal? | ||
850 | Ty::Unknown | ||
851 | } | ||
852 | ast::Expr::IndexExpr(_e) => Ty::Unknown, | 845 | ast::Expr::IndexExpr(_e) => Ty::Unknown, |
853 | ast::Expr::FieldExpr(e) => { | 846 | ast::Expr::FieldExpr(e) => { |
854 | let receiver_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; | 847 | let receiver_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?; |
@@ -1016,7 +1009,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1016 | 1009 | ||
1017 | pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceResult>> { | 1010 | pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceResult>> { |
1018 | let function = Function::new(def_id); // TODO: consts also need inference | 1011 | let function = Function::new(def_id); // TODO: consts also need inference |
1019 | let scopes = function.scopes(db); | 1012 | let scopes = function.scopes(db)?; |
1020 | let module = function.module(db)?; | 1013 | let module = function.module(db)?; |
1021 | let impl_block = function.impl_block(db)?; | 1014 | let impl_block = function.impl_block(db)?; |
1022 | let mut ctx = InferenceContext::new(db, scopes, module, impl_block); | 1015 | let mut ctx = InferenceContext::new(db, scopes, module, impl_block); |