diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-01-06 13:45:22 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-01-06 13:45:22 +0000 |
commit | eaf553dade9a28b41631387d7c88b09fd0ba64e2 (patch) | |
tree | f5043da62c6cf4e2f082f68746843de7dfe53d03 /crates/ra_hir | |
parent | cbac31cbdb2168b18fc6fb89f5cf069238cc6ccb (diff) | |
parent | 98957f4e6f66469310072dff5dfc3e521a7cd555 (diff) |
Merge #441
441: hir::Expr r=matklad a=flodiebold
Still a bit to do, but I already adapted `FnScopes` and thought I'd get feedback already.
Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/src/db.rs | 19 | ||||
-rw-r--r-- | crates/ra_hir/src/expr.rs | 745 | ||||
-rw-r--r-- | crates/ra_hir/src/function.rs | 79 | ||||
-rw-r--r-- | crates/ra_hir/src/function/scope.rs | 368 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir/src/mock.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir/src/name.rs | 14 | ||||
-rw-r--r-- | crates/ra_hir/src/path.rs | 14 | ||||
-rw-r--r-- | crates/ra_hir/src/query_definitions.rs | 11 | ||||
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 19 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 44 | ||||
-rw-r--r-- | crates/ra_hir/src/type_ref.rs | 4 |
13 files changed, 1116 insertions, 219 deletions
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 58296fc6f..96a3c60b9 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -7,7 +7,7 @@ use crate::{ | |||
7 | DefLoc, DefId, MacroCallLoc, MacroCallId, Name, HirFileId, | 7 | DefLoc, DefId, MacroCallLoc, MacroCallId, Name, HirFileId, |
8 | SourceFileItems, SourceItemId, | 8 | SourceFileItems, SourceItemId, |
9 | query_definitions, | 9 | query_definitions, |
10 | FnScopes, | 10 | FnSignature, FnScopes, |
11 | macros::MacroExpansion, | 11 | macros::MacroExpansion, |
12 | module::{ModuleId, ModuleTree, ModuleSource, | 12 | module::{ModuleId, ModuleTree, ModuleSource, |
13 | nameres::{ItemMap, InputModuleItems}}, | 13 | nameres::{ItemMap, InputModuleItems}}, |
@@ -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 | } |
@@ -93,6 +93,21 @@ pub trait HirDatabase: SyntaxDatabase | |||
93 | type ImplsInModuleQuery; | 93 | type ImplsInModuleQuery; |
94 | use fn crate::impl_block::impls_in_module; | 94 | use fn crate::impl_block::impls_in_module; |
95 | } | 95 | } |
96 | |||
97 | fn body_hir(def_id: DefId) -> Cancelable<Arc<crate::expr::Body>> { | ||
98 | type BodyHirQuery; | ||
99 | use fn crate::expr::body_hir; | ||
100 | } | ||
101 | |||
102 | fn body_syntax_mapping(def_id: DefId) -> Cancelable<Arc<crate::expr::BodySyntaxMapping>> { | ||
103 | type BodySyntaxMappingQuery; | ||
104 | use fn crate::expr::body_syntax_mapping; | ||
105 | } | ||
106 | |||
107 | fn fn_signature(def_id: DefId) -> Arc<FnSignature> { | ||
108 | type FnSignatureQuery; | ||
109 | use fn crate::function::fn_signature; | ||
110 | } | ||
96 | } | 111 | } |
97 | 112 | ||
98 | } | 113 | } |
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 | } | ||
diff --git a/crates/ra_hir/src/function.rs b/crates/ra_hir/src/function.rs index 75ef308ae..4627be071 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}, type_ref::{TypeRef, Mutability}, Name}; |
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,25 @@ 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 | }) | ||
54 | } | ||
55 | |||
56 | pub fn signature(&self, db: &impl HirDatabase) -> Arc<FnSignature> { | ||
57 | db.fn_signature(self.def_id) | ||
41 | } | 58 | } |
42 | 59 | ||
43 | pub fn signature_info(&self, db: &impl HirDatabase) -> Option<FnSignatureInfo> { | 60 | pub fn signature_info(&self, db: &impl HirDatabase) -> Option<FnSignatureInfo> { |
@@ -63,6 +80,60 @@ impl Function { | |||
63 | } | 80 | } |
64 | } | 81 | } |
65 | 82 | ||
83 | /// The declared signature of a function. | ||
84 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
85 | pub struct FnSignature { | ||
86 | args: Vec<TypeRef>, | ||
87 | ret_type: TypeRef, | ||
88 | } | ||
89 | |||
90 | impl FnSignature { | ||
91 | pub fn args(&self) -> &[TypeRef] { | ||
92 | &self.args | ||
93 | } | ||
94 | |||
95 | pub fn ret_type(&self) -> &TypeRef { | ||
96 | &self.ret_type | ||
97 | } | ||
98 | } | ||
99 | |||
100 | pub(crate) fn fn_signature(db: &impl HirDatabase, def_id: DefId) -> Arc<FnSignature> { | ||
101 | let func = Function::new(def_id); | ||
102 | let syntax = func.syntax(db); | ||
103 | let node = syntax.borrowed(); | ||
104 | let mut args = Vec::new(); | ||
105 | if let Some(param_list) = node.param_list() { | ||
106 | if let Some(self_param) = param_list.self_param() { | ||
107 | let self_type = if let Some(type_ref) = self_param.type_ref() { | ||
108 | TypeRef::from_ast(type_ref) | ||
109 | } else { | ||
110 | let self_type = TypeRef::Path(Name::self_type().into()); | ||
111 | match self_param.flavor() { | ||
112 | ast::SelfParamFlavor::Owned => self_type, | ||
113 | ast::SelfParamFlavor::Ref => { | ||
114 | TypeRef::Reference(Box::new(self_type), Mutability::Shared) | ||
115 | } | ||
116 | ast::SelfParamFlavor::MutRef => { | ||
117 | TypeRef::Reference(Box::new(self_type), Mutability::Mut) | ||
118 | } | ||
119 | } | ||
120 | }; | ||
121 | args.push(self_type); | ||
122 | } | ||
123 | for param in param_list.params() { | ||
124 | let type_ref = TypeRef::from_ast_opt(param.type_ref()); | ||
125 | args.push(type_ref); | ||
126 | } | ||
127 | } | ||
128 | let ret_type = if let Some(type_ref) = node.ret_type().and_then(|rt| rt.type_ref()) { | ||
129 | TypeRef::from_ast(type_ref) | ||
130 | } else { | ||
131 | TypeRef::unit() | ||
132 | }; | ||
133 | let sig = FnSignature { args, ret_type }; | ||
134 | Arc::new(sig) | ||
135 | } | ||
136 | |||
66 | #[derive(Debug, Clone)] | 137 | #[derive(Debug, Clone)] |
67 | pub struct FnSignatureInfo { | 138 | pub struct FnSignatureInfo { |
68 | pub name: String, | 139 | pub name: String, |
diff --git a/crates/ra_hir/src/function/scope.rs b/crates/ra_hir/src/function/scope.rs index 42bfe4f32..0a12f0b35 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,100 @@ 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 | .find(|entry| entry.name() == &name); | ||
70 | ret | ||
71 | } | ||
72 | |||
73 | fn root_scope(&mut self) -> ScopeId { | ||
74 | self.scopes.alloc(ScopeData { | ||
75 | parent: None, | ||
76 | entries: vec![], | ||
77 | }) | ||
78 | } | ||
79 | fn new_scope(&mut self, parent: ScopeId) -> ScopeId { | ||
80 | self.scopes.alloc(ScopeData { | ||
81 | parent: Some(parent), | ||
82 | entries: vec![], | ||
83 | }) | ||
84 | } | ||
85 | fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { | ||
86 | match &body[pat] { | ||
87 | Pat::Bind { name } => self.scopes[scope].entries.push(ScopeEntry { | ||
88 | name: name.clone(), | ||
89 | pat, | ||
90 | }), | ||
91 | p => p.walk_child_pats(|pat| self.add_bindings(body, scope, pat)), | ||
92 | } | ||
93 | } | ||
94 | fn add_params_bindings(&mut self, scope: ScopeId, params: &[PatId]) { | ||
95 | let body = Arc::clone(&self.body); | ||
96 | params | ||
97 | .into_iter() | ||
98 | .for_each(|pat| self.add_bindings(&body, scope, *pat)); | ||
99 | } | ||
100 | fn set_scope(&mut self, node: ExprId, scope: ScopeId) { | ||
101 | self.scope_for.insert(node, scope); | ||
102 | } | ||
103 | fn scope_for(&self, expr: ExprId) -> Option<ScopeId> { | ||
104 | self.scope_for.get(&expr).map(|&scope| scope) | ||
105 | } | ||
106 | } | ||
107 | |||
108 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
109 | pub struct ScopesWithSyntaxMapping { | ||
110 | pub syntax_mapping: Arc<BodySyntaxMapping>, | ||
111 | pub scopes: Arc<FnScopes>, | ||
112 | } | ||
113 | |||
114 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
115 | pub struct ScopeEntryWithSyntax { | ||
116 | name: Name, | ||
117 | ptr: LocalSyntaxPtr, | ||
118 | } | ||
119 | |||
120 | impl ScopeEntryWithSyntax { | ||
121 | pub fn name(&self) -> &Name { | ||
122 | &self.name | ||
123 | } | ||
124 | pub fn ptr(&self) -> LocalSyntaxPtr { | ||
125 | self.ptr | ||
126 | } | ||
127 | } | ||
128 | |||
129 | impl ScopesWithSyntaxMapping { | ||
56 | pub fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item = ScopeId> + 'a { | 130 | pub fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item = ScopeId> + 'a { |
57 | generate(self.scope_for(node), move |&scope| { | 131 | generate(self.scope_for(node), move |&scope| { |
58 | self.scopes[scope].parent | 132 | self.scopes.scopes[scope].parent |
59 | }) | 133 | }) |
60 | } | 134 | } |
61 | pub fn scope_chain_for_offset<'a>( | 135 | pub fn scope_chain_for_offset<'a>( |
@@ -63,26 +137,30 @@ impl FnScopes { | |||
63 | offset: TextUnit, | 137 | offset: TextUnit, |
64 | ) -> impl Iterator<Item = ScopeId> + 'a { | 138 | ) -> impl Iterator<Item = ScopeId> + 'a { |
65 | let scope = self | 139 | let scope = self |
140 | .scopes | ||
66 | .scope_for | 141 | .scope_for |
67 | .iter() | 142 | .iter() |
68 | // find containin scope | 143 | .filter_map(|(id, scope)| Some((self.syntax_mapping.expr_syntax(*id)?, scope))) |
144 | // find containing scope | ||
69 | .min_by_key(|(ptr, _scope)| { | 145 | .min_by_key(|(ptr, _scope)| { |
70 | ( | 146 | ( |
71 | !(ptr.range().start() <= offset && offset <= ptr.range().end()), | 147 | !(ptr.range().start() <= offset && offset <= ptr.range().end()), |
72 | ptr.range().len(), | 148 | ptr.range().len(), |
73 | ) | 149 | ) |
74 | }) | 150 | }) |
75 | .map(|(ptr, scope)| self.adjust(*ptr, *scope, offset)); | 151 | .map(|(ptr, scope)| self.adjust(ptr, *scope, offset)); |
76 | 152 | ||
77 | generate(scope, move |&scope| self.scopes[scope].parent) | 153 | generate(scope, move |&scope| self.scopes.scopes[scope].parent) |
78 | } | 154 | } |
79 | // XXX: during completion, cursor might be outside of any particular | 155 | // XXX: during completion, cursor might be outside of any particular |
80 | // expression. Try to figure out the correct scope... | 156 | // expression. Try to figure out the correct scope... |
81 | fn adjust(&self, ptr: LocalSyntaxPtr, original_scope: ScopeId, offset: TextUnit) -> ScopeId { | 157 | fn adjust(&self, ptr: LocalSyntaxPtr, original_scope: ScopeId, offset: TextUnit) -> ScopeId { |
82 | let r = ptr.range(); | 158 | let r = ptr.range(); |
83 | let child_scopes = self | 159 | let child_scopes = self |
160 | .scopes | ||
84 | .scope_for | 161 | .scope_for |
85 | .iter() | 162 | .iter() |
163 | .filter_map(|(id, scope)| Some((self.syntax_mapping.expr_syntax(*id)?, scope))) | ||
86 | .map(|(ptr, scope)| (ptr.range(), scope)) | 164 | .map(|(ptr, scope)| (ptr.range(), scope)) |
87 | .filter(|(range, _)| range.start() <= offset && range.is_subrange(&r) && *range != r); | 165 | .filter(|(range, _)| range.start() <= offset && range.is_subrange(&r) && *range != r); |
88 | 166 | ||
@@ -100,22 +178,27 @@ impl FnScopes { | |||
100 | .unwrap_or(original_scope) | 178 | .unwrap_or(original_scope) |
101 | } | 179 | } |
102 | 180 | ||
103 | pub fn resolve_local_name<'a>(&'a self, name_ref: ast::NameRef) -> Option<&'a ScopeEntry> { | 181 | pub fn resolve_local_name(&self, name_ref: ast::NameRef) -> Option<ScopeEntryWithSyntax> { |
104 | let mut shadowed = FxHashSet::default(); | 182 | let mut shadowed = FxHashSet::default(); |
105 | let name = name_ref.as_name(); | 183 | let name = name_ref.as_name(); |
106 | let ret = self | 184 | let ret = self |
107 | .scope_chain(name_ref.syntax()) | 185 | .scope_chain(name_ref.syntax()) |
108 | .flat_map(|scope| self.entries(scope).iter()) | 186 | .flat_map(|scope| self.scopes.entries(scope).iter()) |
109 | .filter(|entry| shadowed.insert(entry.name())) | 187 | .filter(|entry| shadowed.insert(entry.name())) |
110 | .filter(|entry| entry.name() == &name) | 188 | .filter(|entry| entry.name() == &name) |
111 | .nth(0); | 189 | .nth(0); |
112 | ret | 190 | ret.and_then(|entry| { |
191 | Some(ScopeEntryWithSyntax { | ||
192 | name: entry.name().clone(), | ||
193 | ptr: self.syntax_mapping.pat_syntax(entry.pat())?, | ||
194 | }) | ||
195 | }) | ||
113 | } | 196 | } |
114 | 197 | ||
115 | pub fn find_all_refs(&self, pat: ast::BindPat) -> Vec<ReferenceDescriptor> { | 198 | pub fn find_all_refs(&self, pat: ast::BindPat) -> Vec<ReferenceDescriptor> { |
116 | let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); | 199 | let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); |
117 | let name_ptr = LocalSyntaxPtr::new(pat.syntax()); | 200 | let name_ptr = LocalSyntaxPtr::new(pat.syntax()); |
118 | let refs: Vec<_> = fn_def | 201 | fn_def |
119 | .syntax() | 202 | .syntax() |
120 | .descendants() | 203 | .descendants() |
121 | .filter_map(ast::NameRef::cast) | 204 | .filter_map(ast::NameRef::cast) |
@@ -127,203 +210,94 @@ impl FnScopes { | |||
127 | name: name_ref.syntax().text().to_string(), | 210 | name: name_ref.syntax().text().to_string(), |
128 | range: name_ref.syntax().range(), | 211 | range: name_ref.syntax().range(), |
129 | }) | 212 | }) |
130 | .collect(); | 213 | .collect() |
131 | |||
132 | refs | ||
133 | } | 214 | } |
134 | 215 | ||
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> { | 216 | fn scope_for(&self, node: SyntaxNodeRef) -> Option<ScopeId> { |
166 | node.ancestors() | 217 | node.ancestors() |
167 | .map(LocalSyntaxPtr::new) | 218 | .map(LocalSyntaxPtr::new) |
168 | .filter_map(|it| self.scope_for.get(&it).map(|&scope| scope)) | 219 | .filter_map(|ptr| self.syntax_mapping.syntax_expr(ptr)) |
169 | .next() | 220 | .find_map(|it| self.scopes.scope_for(it)) |
170 | } | 221 | } |
171 | } | 222 | } |
172 | 223 | ||
173 | impl ScopeEntry { | 224 | 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 { | 225 | pub fn name(&self) -> &Name { |
183 | &self.name | 226 | &self.name |
184 | } | 227 | } |
185 | pub fn ptr(&self) -> LocalSyntaxPtr { | 228 | pub fn pat(&self) -> PatId { |
186 | self.ptr | 229 | self.pat |
187 | } | 230 | } |
188 | } | 231 | } |
189 | 232 | ||
190 | fn compute_block_scopes(block: ast::Block, scopes: &mut FnScopes, mut scope: ScopeId) { | 233 | fn compute_block_scopes( |
191 | // A hack for completion :( | 234 | statements: &[Statement], |
192 | scopes.set_scope(block.syntax(), scope); | 235 | tail: Option<ExprId>, |
193 | for stmt in block.statements() { | 236 | body: &Body, |
237 | scopes: &mut FnScopes, | ||
238 | mut scope: ScopeId, | ||
239 | ) { | ||
240 | for stmt in statements { | ||
194 | match stmt { | 241 | match stmt { |
195 | ast::Stmt::LetStmt(stmt) => { | 242 | Statement::Let { |
196 | if let Some(expr) = stmt.initializer() { | 243 | pat, initializer, .. |
197 | scopes.set_scope(expr.syntax(), scope); | 244 | } => { |
198 | compute_expr_scopes(expr, scopes, scope); | 245 | if let Some(expr) = initializer { |
246 | scopes.set_scope(*expr, scope); | ||
247 | compute_expr_scopes(*expr, body, scopes, scope); | ||
199 | } | 248 | } |
200 | scope = scopes.new_scope(scope); | 249 | scope = scopes.new_scope(scope); |
201 | if let Some(pat) = stmt.pat() { | 250 | scopes.add_bindings(body, scope, *pat); |
202 | scopes.add_bindings(scope, pat); | ||
203 | } | ||
204 | } | 251 | } |
205 | ast::Stmt::ExprStmt(expr_stmt) => { | 252 | Statement::Expr(expr) => { |
206 | if let Some(expr) = expr_stmt.expr() { | 253 | scopes.set_scope(*expr, scope); |
207 | scopes.set_scope(expr.syntax(), scope); | 254 | compute_expr_scopes(*expr, body, scopes, scope); |
208 | compute_expr_scopes(expr, scopes, scope); | ||
209 | } | ||
210 | } | 255 | } |
211 | } | 256 | } |
212 | } | 257 | } |
213 | if let Some(expr) = block.expr() { | 258 | if let Some(expr) = tail { |
214 | scopes.set_scope(expr.syntax(), scope); | 259 | compute_expr_scopes(expr, body, scopes, scope); |
215 | compute_expr_scopes(expr, scopes, scope); | ||
216 | } | 260 | } |
217 | } | 261 | } |
218 | 262 | ||
219 | fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) { | 263 | fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut FnScopes, scope: ScopeId) { |
220 | match expr { | 264 | scopes.set_scope(expr, scope); |
221 | ast::Expr::IfExpr(e) => { | 265 | match &body[expr] { |
222 | let cond_scope = e | 266 | Expr::Block { statements, tail } => { |
223 | .condition() | 267 | 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 | } | 268 | } |
250 | ast::Expr::ForExpr(e) => { | 269 | Expr::For { |
251 | if let Some(expr) = e.iterable() { | 270 | iterable, |
252 | compute_expr_scopes(expr, scopes, scope); | 271 | pat, |
253 | } | 272 | body: body_expr, |
254 | let mut scope = scope; | 273 | } => { |
255 | if let Some(pat) = e.pat() { | 274 | 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); | 275 | let scope = scopes.new_scope(scope); |
265 | scopes.add_params_bindings(scope, e.param_list()); | 276 | scopes.add_bindings(body, scope, *pat); |
266 | if let Some(body) = e.body() { | 277 | compute_expr_scopes(*body_expr, body, scopes, scope); |
267 | scopes.set_scope(body.syntax(), scope); | ||
268 | compute_expr_scopes(body, scopes, scope); | ||
269 | } | ||
270 | } | 278 | } |
271 | ast::Expr::CallExpr(e) => { | 279 | Expr::Lambda { |
272 | compute_call_scopes(e.expr(), e.arg_list(), scopes, scope); | 280 | args, |
273 | } | 281 | body: body_expr, |
274 | ast::Expr::MethodCallExpr(e) => { | 282 | .. |
275 | compute_call_scopes(e.expr(), e.arg_list(), scopes, scope); | 283 | } => { |
284 | let scope = scopes.new_scope(scope); | ||
285 | scopes.add_params_bindings(scope, &args); | ||
286 | compute_expr_scopes(*body_expr, body, scopes, scope); | ||
276 | } | 287 | } |
277 | ast::Expr::MatchExpr(e) => { | 288 | Expr::Match { expr, arms } => { |
278 | if let Some(expr) = e.expr() { | 289 | compute_expr_scopes(*expr, body, scopes, scope); |
279 | compute_expr_scopes(expr, scopes, scope); | 290 | 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); | 291 | let scope = scopes.new_scope(scope); |
283 | for pat in arm.pats() { | 292 | for pat in &arm.pats { |
284 | scopes.add_bindings(scope, pat); | 293 | scopes.add_bindings(body, scope, *pat); |
285 | } | ||
286 | if let Some(expr) = arm.expr() { | ||
287 | compute_expr_scopes(expr, scopes, scope); | ||
288 | } | 294 | } |
295 | scopes.set_scope(arm.expr, scope); | ||
296 | compute_expr_scopes(arm.expr, body, scopes, scope); | ||
289 | } | 297 | } |
290 | } | 298 | } |
291 | _ => expr | 299 | 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 | }; | 300 | }; |
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 | } | 301 | } |
328 | 302 | ||
329 | #[derive(Debug)] | 303 | #[derive(Debug)] |
@@ -338,6 +312,8 @@ mod tests { | |||
338 | use ra_syntax::SourceFileNode; | 312 | use ra_syntax::SourceFileNode; |
339 | use test_utils::{extract_offset, assert_eq_text}; | 313 | use test_utils::{extract_offset, assert_eq_text}; |
340 | 314 | ||
315 | use crate::expr; | ||
316 | |||
341 | use super::*; | 317 | use super::*; |
342 | 318 | ||
343 | fn do_check(code: &str, expected: &[&str]) { | 319 | fn do_check(code: &str, expected: &[&str]) { |
@@ -353,15 +329,20 @@ mod tests { | |||
353 | let file = SourceFileNode::parse(&code); | 329 | let file = SourceFileNode::parse(&code); |
354 | let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); | 330 | 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(); | 331 | let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); |
356 | let scopes = FnScopes::new(fn_def); | 332 | let body_hir = expr::collect_fn_body_syntax(fn_def); |
333 | let scopes = FnScopes::new(Arc::clone(body_hir.body())); | ||
334 | let scopes = ScopesWithSyntaxMapping { | ||
335 | scopes: Arc::new(scopes), | ||
336 | syntax_mapping: Arc::new(body_hir), | ||
337 | }; | ||
357 | let actual = scopes | 338 | let actual = scopes |
358 | .scope_chain(marker.syntax()) | 339 | .scope_chain(marker.syntax()) |
359 | .flat_map(|scope| scopes.entries(scope)) | 340 | .flat_map(|scope| scopes.scopes.entries(scope)) |
360 | .map(|it| it.name().to_string()) | 341 | .map(|it| it.name().to_string()) |
361 | .collect::<Vec<_>>() | 342 | .collect::<Vec<_>>() |
362 | .join("\n"); | 343 | .join("\n"); |
363 | let expected = expected.join("\n"); | 344 | let expected = expected.join("\n"); |
364 | assert_eq_text!(&actual, &expected); | 345 | assert_eq_text!(&expected, &actual); |
365 | } | 346 | } |
366 | 347 | ||
367 | #[test] | 348 | #[test] |
@@ -389,7 +370,7 @@ mod tests { | |||
389 | } | 370 | } |
390 | 371 | ||
391 | #[test] | 372 | #[test] |
392 | fn test_metod_call_scope() { | 373 | fn test_method_call_scope() { |
393 | do_check( | 374 | do_check( |
394 | r" | 375 | r" |
395 | fn quux() { | 376 | fn quux() { |
@@ -445,10 +426,15 @@ mod tests { | |||
445 | let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); | 426 | 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(); | 427 | let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); |
447 | 428 | ||
448 | let scopes = FnScopes::new(fn_def); | 429 | let body_hir = expr::collect_fn_body_syntax(fn_def); |
430 | let scopes = FnScopes::new(Arc::clone(body_hir.body())); | ||
431 | let scopes = ScopesWithSyntaxMapping { | ||
432 | scopes: Arc::new(scopes), | ||
433 | syntax_mapping: Arc::new(body_hir), | ||
434 | }; | ||
449 | 435 | ||
450 | let local_name_entry = scopes.resolve_local_name(name_ref).unwrap(); | 436 | let local_name_entry = scopes.resolve_local_name(name_ref).unwrap(); |
451 | let local_name = local_name_entry.ptr().resolve(&file); | 437 | let local_name = local_name_entry.ptr(); |
452 | let expected_name = | 438 | let expected_name = |
453 | find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()).unwrap(); | 439 | find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()).unwrap(); |
454 | assert_eq!(local_name.range(), expected_name.syntax().range()); | 440 | 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 2abcec441..d600b91df 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -32,6 +32,7 @@ mod adt; | |||
32 | mod type_ref; | 32 | mod type_ref; |
33 | mod ty; | 33 | mod ty; |
34 | mod impl_block; | 34 | mod impl_block; |
35 | mod expr; | ||
35 | 36 | ||
36 | use crate::{ | 37 | use crate::{ |
37 | db::HirDatabase, | 38 | db::HirDatabase, |
@@ -46,7 +47,7 @@ pub use self::{ | |||
46 | ids::{HirFileId, DefId, DefLoc, MacroCallId, MacroCallLoc}, | 47 | ids::{HirFileId, DefId, DefLoc, MacroCallId, MacroCallLoc}, |
47 | macros::{MacroDef, MacroInput, MacroExpansion}, | 48 | macros::{MacroDef, MacroInput, MacroExpansion}, |
48 | module::{Module, ModuleId, Problem, nameres::{ItemMap, PerNs, Namespace}, ModuleScope, Resolution}, | 49 | module::{Module, ModuleId, Problem, nameres::{ItemMap, PerNs, Namespace}, ModuleScope, Resolution}, |
49 | function::{Function, FnScopes}, | 50 | function::{Function, FnSignature, FnScopes, ScopesWithSyntaxMapping}, |
50 | adt::{Struct, Enum}, | 51 | adt::{Struct, Enum}, |
51 | ty::Ty, | 52 | ty::Ty, |
52 | impl_block::{ImplBlock, ImplItem}, | 53 | impl_block::{ImplBlock, ImplItem}, |
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs index a9db932ff..8d176662c 100644 --- a/crates/ra_hir/src/mock.rs +++ b/crates/ra_hir/src/mock.rs | |||
@@ -208,6 +208,9 @@ salsa::database_storage! { | |||
208 | fn struct_data() for db::StructDataQuery; | 208 | fn struct_data() for db::StructDataQuery; |
209 | fn enum_data() for db::EnumDataQuery; | 209 | fn enum_data() for db::EnumDataQuery; |
210 | fn impls_in_module() for db::ImplsInModuleQuery; | 210 | fn impls_in_module() for db::ImplsInModuleQuery; |
211 | fn body_hir() for db::BodyHirQuery; | ||
212 | fn body_syntax_mapping() for db::BodySyntaxMappingQuery; | ||
213 | fn fn_signature() for db::FnSignatureQuery; | ||
211 | } | 214 | } |
212 | } | 215 | } |
213 | } | 216 | } |
diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs index 017caf442..90229bc54 100644 --- a/crates/ra_hir/src/name.rs +++ b/crates/ra_hir/src/name.rs | |||
@@ -31,6 +31,14 @@ 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 | |||
38 | pub(crate) fn self_type() -> Name { | ||
39 | Name::new("Self".into()) | ||
40 | } | ||
41 | |||
34 | pub(crate) fn tuple_field_name(idx: usize) -> Name { | 42 | pub(crate) fn tuple_field_name(idx: usize) -> Name { |
35 | Name::new(idx.to_string().into()) | 43 | Name::new(idx.to_string().into()) |
36 | } | 44 | } |
@@ -51,7 +59,8 @@ impl Name { | |||
51 | "u128" => KnownName::U128, | 59 | "u128" => KnownName::U128, |
52 | "f32" => KnownName::F32, | 60 | "f32" => KnownName::F32, |
53 | "f64" => KnownName::F64, | 61 | "f64" => KnownName::F64, |
54 | "Self" => KnownName::Self_, | 62 | "Self" => KnownName::SelfType, |
63 | "self" => KnownName::SelfParam, | ||
55 | _ => return None, | 64 | _ => return None, |
56 | }; | 65 | }; |
57 | Some(name) | 66 | Some(name) |
@@ -104,5 +113,6 @@ pub(crate) enum KnownName { | |||
104 | F32, | 113 | F32, |
105 | F64, | 114 | F64, |
106 | 115 | ||
107 | Self_, | 116 | SelfType, |
117 | SelfParam, | ||
108 | } | 118 | } |
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index 9fdfa0d13..dcf4cf8b6 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs | |||
@@ -65,6 +65,11 @@ impl Path { | |||
65 | } | 65 | } |
66 | } | 66 | } |
67 | 67 | ||
68 | /// Converts an `ast::NameRef` into a single-identifier `Path`. | ||
69 | pub fn from_name_ref(name_ref: ast::NameRef) -> Path { | ||
70 | name_ref.as_name().into() | ||
71 | } | ||
72 | |||
68 | /// `true` is this path is a single identifier, like `foo` | 73 | /// `true` is this path is a single identifier, like `foo` |
69 | pub fn is_ident(&self) -> bool { | 74 | pub fn is_ident(&self) -> bool { |
70 | self.kind == PathKind::Plain && self.segments.len() == 1 | 75 | self.kind == PathKind::Plain && self.segments.len() == 1 |
@@ -84,6 +89,15 @@ impl Path { | |||
84 | } | 89 | } |
85 | } | 90 | } |
86 | 91 | ||
92 | impl From<Name> for Path { | ||
93 | fn from(name: Name) -> Path { | ||
94 | Path { | ||
95 | kind: PathKind::Plain, | ||
96 | segments: vec![name], | ||
97 | } | ||
98 | } | ||
99 | } | ||
100 | |||
87 | fn expand_use_tree( | 101 | fn expand_use_tree( |
88 | prefix: Option<Path>, | 102 | prefix: Option<Path>, |
89 | tree: ast::UseTree, | 103 | tree: ast::UseTree, |
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/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 85bd84469..29a3960e9 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -87,6 +87,18 @@ fn module_from_source( | |||
87 | Ok(Some(Module::new(db, source_root_id, module_id)?)) | 87 | Ok(Some(Module::new(db, source_root_id, module_id)?)) |
88 | } | 88 | } |
89 | 89 | ||
90 | pub fn function_from_position( | ||
91 | db: &impl HirDatabase, | ||
92 | position: FilePosition, | ||
93 | ) -> Cancelable<Option<Function>> { | ||
94 | let file = db.source_file(position.file_id); | ||
95 | let fn_def = ctry!(find_node_at_offset::<ast::FnDef>( | ||
96 | file.syntax(), | ||
97 | position.offset | ||
98 | )); | ||
99 | function_from_source(db, position.file_id, fn_def) | ||
100 | } | ||
101 | |||
90 | pub fn function_from_source( | 102 | pub fn function_from_source( |
91 | db: &impl HirDatabase, | 103 | db: &impl HirDatabase, |
92 | file_id: FileId, | 104 | file_id: FileId, |
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); |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index fb53fcf0b..515c66e85 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -1,7 +1,10 @@ | |||
1 | use std::sync::Arc; | ||
1 | use std::fmt::Write; | 2 | use std::fmt::Write; |
2 | use std::path::{PathBuf, Path}; | 3 | use std::path::{PathBuf, Path}; |
3 | use std::fs; | 4 | use std::fs; |
4 | 5 | ||
6 | use salsa::Database; | ||
7 | |||
5 | use ra_db::{SyntaxDatabase}; | 8 | use ra_db::{SyntaxDatabase}; |
6 | use ra_syntax::ast::{self, AstNode}; | 9 | use ra_syntax::ast::{self, AstNode}; |
7 | use test_utils::{project_dir, assert_eq_text, read_text}; | 10 | use test_utils::{project_dir, assert_eq_text, read_text}; |
@@ -217,3 +220,44 @@ fn ellipsize(mut text: String, max_len: usize) -> String { | |||
217 | fn test_data_dir() -> PathBuf { | 220 | fn test_data_dir() -> PathBuf { |
218 | project_dir().join("crates/ra_hir/src/ty/tests/data") | 221 | project_dir().join("crates/ra_hir/src/ty/tests/data") |
219 | } | 222 | } |
223 | |||
224 | #[test] | ||
225 | #[should_panic] // TODO this should work once hir::Expr is used | ||
226 | fn typing_whitespace_inside_a_function_should_not_invalidate_types() { | ||
227 | let (mut db, pos) = MockDatabase::with_position( | ||
228 | " | ||
229 | //- /lib.rs | ||
230 | fn foo() -> i32 { | ||
231 | <|>1 + 1 | ||
232 | } | ||
233 | ", | ||
234 | ); | ||
235 | let func = source_binder::function_from_position(&db, pos) | ||
236 | .unwrap() | ||
237 | .unwrap(); | ||
238 | { | ||
239 | let events = db.log_executed(|| { | ||
240 | func.infer(&db).unwrap(); | ||
241 | }); | ||
242 | assert!(format!("{:?}", events).contains("infer")) | ||
243 | } | ||
244 | |||
245 | let new_text = " | ||
246 | fn foo() -> i32 { | ||
247 | 1 | ||
248 | + | ||
249 | 1 | ||
250 | } | ||
251 | " | ||
252 | .to_string(); | ||
253 | |||
254 | db.query_mut(ra_db::FileTextQuery) | ||
255 | .set(pos.file_id, Arc::new(new_text)); | ||
256 | |||
257 | { | ||
258 | let events = db.log_executed(|| { | ||
259 | func.infer(&db).unwrap(); | ||
260 | }); | ||
261 | assert!(!format!("{:?}", events).contains("infer"), "{:#?}", events) | ||
262 | } | ||
263 | } | ||
diff --git a/crates/ra_hir/src/type_ref.rs b/crates/ra_hir/src/type_ref.rs index b36bb35d8..859f330c2 100644 --- a/crates/ra_hir/src/type_ref.rs +++ b/crates/ra_hir/src/type_ref.rs | |||
@@ -107,4 +107,8 @@ impl TypeRef { | |||
107 | TypeRef::Error | 107 | TypeRef::Error |
108 | } | 108 | } |
109 | } | 109 | } |
110 | |||
111 | pub fn unit() -> TypeRef { | ||
112 | TypeRef::Tuple(Vec::new()) | ||
113 | } | ||
110 | } | 114 | } |