aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-01-06 13:45:22 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-01-06 13:45:22 +0000
commiteaf553dade9a28b41631387d7c88b09fd0ba64e2 (patch)
treef5043da62c6cf4e2f082f68746843de7dfe53d03 /crates
parentcbac31cbdb2168b18fc6fb89f5cf069238cc6ccb (diff)
parent98957f4e6f66469310072dff5dfc3e521a7cd555 (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')
-rw-r--r--crates/ra_analysis/src/completion/complete_scope.rs9
-rw-r--r--crates/ra_analysis/src/db.rs3
-rw-r--r--crates/ra_analysis/src/goto_defenition.rs2
-rw-r--r--crates/ra_analysis/src/imp.rs4
-rw-r--r--crates/ra_db/src/syntax_ptr.rs2
-rw-r--r--crates/ra_hir/src/db.rs19
-rw-r--r--crates/ra_hir/src/expr.rs745
-rw-r--r--crates/ra_hir/src/function.rs79
-rw-r--r--crates/ra_hir/src/function/scope.rs368
-rw-r--r--crates/ra_hir/src/lib.rs3
-rw-r--r--crates/ra_hir/src/mock.rs3
-rw-r--r--crates/ra_hir/src/name.rs14
-rw-r--r--crates/ra_hir/src/path.rs14
-rw-r--r--crates/ra_hir/src/query_definitions.rs11
-rw-r--r--crates/ra_hir/src/source_binder.rs12
-rw-r--r--crates/ra_hir/src/ty.rs19
-rw-r--r--crates/ra_hir/src/ty/tests.rs44
-rw-r--r--crates/ra_hir/src/type_ref.rs4
-rw-r--r--crates/ra_syntax/src/ast/generated.rs35
-rw-r--r--crates/ra_syntax/src/grammar.ron14
20 files changed, 1150 insertions, 254 deletions
diff --git a/crates/ra_analysis/src/completion/complete_scope.rs b/crates/ra_analysis/src/completion/complete_scope.rs
index 4dead3689..21d77aa97 100644
--- a/crates/ra_analysis/src/completion/complete_scope.rs
+++ b/crates/ra_analysis/src/completion/complete_scope.rs
@@ -15,7 +15,7 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) ->
15 None => return Ok(()), 15 None => return Ok(()),
16 }; 16 };
17 if let Some(function) = &ctx.function { 17 if let Some(function) = &ctx.function {
18 let scopes = function.scopes(ctx.db); 18 let scopes = function.scopes(ctx.db)?;
19 complete_fn(acc, &scopes, ctx.offset); 19 complete_fn(acc, &scopes, ctx.offset);
20 } 20 }
21 21
@@ -40,20 +40,17 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) ->
40 Ok(()) 40 Ok(())
41} 41}
42 42
43fn complete_fn(acc: &mut Completions, scopes: &hir::FnScopes, offset: TextUnit) { 43fn complete_fn(acc: &mut Completions, scopes: &hir::ScopesWithSyntaxMapping, offset: TextUnit) {
44 let mut shadowed = FxHashSet::default(); 44 let mut shadowed = FxHashSet::default();
45 scopes 45 scopes
46 .scope_chain_for_offset(offset) 46 .scope_chain_for_offset(offset)
47 .flat_map(|scope| scopes.entries(scope).iter()) 47 .flat_map(|scope| scopes.scopes.entries(scope).iter())
48 .filter(|entry| shadowed.insert(entry.name())) 48 .filter(|entry| shadowed.insert(entry.name()))
49 .for_each(|entry| { 49 .for_each(|entry| {
50 CompletionItem::new(CompletionKind::Reference, entry.name().to_string()) 50 CompletionItem::new(CompletionKind::Reference, entry.name().to_string())
51 .kind(CompletionItemKind::Binding) 51 .kind(CompletionItemKind::Binding)
52 .add_to(acc) 52 .add_to(acc)
53 }); 53 });
54 if scopes.self_param.is_some() {
55 CompletionItem::new(CompletionKind::Reference, "self").add_to(acc);
56 }
57} 54}
58 55
59#[cfg(test)] 56#[cfg(test)]
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs
index 5422a400b..1709be5cf 100644
--- a/crates/ra_analysis/src/db.rs
+++ b/crates/ra_analysis/src/db.rs
@@ -106,6 +106,9 @@ salsa::database_storage! {
106 fn struct_data() for hir::db::StructDataQuery; 106 fn struct_data() for hir::db::StructDataQuery;
107 fn enum_data() for hir::db::EnumDataQuery; 107 fn enum_data() for hir::db::EnumDataQuery;
108 fn impls_in_module() for hir::db::ImplsInModuleQuery; 108 fn impls_in_module() for hir::db::ImplsInModuleQuery;
109 fn body_hir() for hir::db::BodyHirQuery;
110 fn body_syntax_mapping() for hir::db::BodySyntaxMappingQuery;
111 fn fn_signature() for hir::db::FnSignatureQuery;
109 } 112 }
110 } 113 }
111} 114}
diff --git a/crates/ra_analysis/src/goto_defenition.rs b/crates/ra_analysis/src/goto_defenition.rs
index e37421f8d..68b6ac3ba 100644
--- a/crates/ra_analysis/src/goto_defenition.rs
+++ b/crates/ra_analysis/src/goto_defenition.rs
@@ -28,7 +28,7 @@ pub(crate) fn reference_defenition(
28 if let Some(fn_descr) = 28 if let Some(fn_descr) =
29 hir::source_binder::function_from_child_node(db, file_id, name_ref.syntax())? 29 hir::source_binder::function_from_child_node(db, file_id, name_ref.syntax())?
30 { 30 {
31 let scope = fn_descr.scopes(db); 31 let scope = fn_descr.scopes(db)?;
32 // First try to resolve the symbol locally 32 // First try to resolve the symbol locally
33 if let Some(entry) = scope.resolve_local_name(name_ref) { 33 if let Some(entry) = scope.resolve_local_name(name_ref) {
34 let nav = NavigationTarget { 34 let nav = NavigationTarget {
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index 6ab3c5476..5988fb779 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -157,7 +157,7 @@ impl db::RootDatabase {
157 .collect::<Vec<_>>(); 157 .collect::<Vec<_>>();
158 ret.extend( 158 ret.extend(
159 descr 159 descr
160 .scopes(self) 160 .scopes(self)?
161 .find_all_refs(binding) 161 .find_all_refs(binding)
162 .into_iter() 162 .into_iter()
163 .map(|ref_desc| (position.file_id, ref_desc.range)), 163 .map(|ref_desc| (position.file_id, ref_desc.range)),
@@ -185,7 +185,7 @@ impl db::RootDatabase {
185 position.file_id, 185 position.file_id,
186 name_ref.syntax(), 186 name_ref.syntax(),
187 )?); 187 )?);
188 let scope = descr.scopes(db); 188 let scope = descr.scopes(db)?;
189 let resolved = ctry!(scope.resolve_local_name(name_ref)); 189 let resolved = ctry!(scope.resolve_local_name(name_ref));
190 let resolved = resolved.ptr().resolve(source_file); 190 let resolved = resolved.ptr().resolve(source_file);
191 let binding = ctry!(find_node_at_offset::<ast::BindPat>( 191 let binding = ctry!(find_node_at_offset::<ast::BindPat>(
diff --git a/crates/ra_db/src/syntax_ptr.rs b/crates/ra_db/src/syntax_ptr.rs
index 744cb2352..5bfcedf2b 100644
--- a/crates/ra_db/src/syntax_ptr.rs
+++ b/crates/ra_db/src/syntax_ptr.rs
@@ -1,6 +1,6 @@
1use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, TextRange}; 1use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, TextRange};
2 2
3/// A pionter to a syntax node inside a file. 3/// A pointer to a syntax node inside a file.
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5pub struct LocalSyntaxPtr { 5pub struct LocalSyntaxPtr {
6 range: TextRange, 6 range: TextRange,
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 @@
1use std::ops::Index;
2use std::sync::Arc;
3
4use rustc_hash::FxHashMap;
5
6use ra_arena::{Arena, RawId, impl_arena_id};
7use ra_db::{LocalSyntaxPtr, Cancelable};
8use ra_syntax::ast::{self, AstNode, LoopBodyOwner, ArgListOwner, NameOwner};
9
10use crate::{Path, type_ref::{Mutability, TypeRef}, Name, HirDatabase, DefId, Def, name::AsName};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
13pub struct ExprId(RawId);
14impl_arena_id!(ExprId);
15
16/// The body of an item (function, const etc.).
17#[derive(Debug, Eq, PartialEq)]
18pub struct Body {
19 exprs: Arena<ExprId, Expr>,
20 pats: Arena<PatId, Pat>,
21 /// The patterns for the function's arguments. While the argument types are
22 /// part of the function signature, the patterns are not (they don't change
23 /// the external type of the function).
24 ///
25 /// If this `Body` is for the body of a constant, this will just be
26 /// empty.
27 args: Vec<PatId>,
28 /// The `ExprId` of the actual body expression.
29 body_expr: ExprId,
30}
31
32/// An item body together with the mapping from syntax nodes to HIR expression
33/// IDs. This is needed to go from e.g. a position in a file to the HIR
34/// expression containing it; but for type inference etc., we want to operate on
35/// a structure that is agnostic to the actual positions of expressions in the
36/// file, so that we don't recompute the type inference whenever some whitespace
37/// is typed.
38#[derive(Debug, Eq, PartialEq)]
39pub struct BodySyntaxMapping {
40 body: Arc<Body>,
41 expr_syntax_mapping: FxHashMap<LocalSyntaxPtr, ExprId>,
42 expr_syntax_mapping_back: FxHashMap<ExprId, LocalSyntaxPtr>,
43 pat_syntax_mapping: FxHashMap<LocalSyntaxPtr, PatId>,
44 pat_syntax_mapping_back: FxHashMap<PatId, LocalSyntaxPtr>,
45}
46
47impl Body {
48 pub fn args(&self) -> &[PatId] {
49 &self.args
50 }
51
52 pub fn body_expr(&self) -> ExprId {
53 self.body_expr
54 }
55}
56
57impl Index<ExprId> for Body {
58 type Output = Expr;
59
60 fn index(&self, expr: ExprId) -> &Expr {
61 &self.exprs[expr]
62 }
63}
64
65impl Index<PatId> for Body {
66 type Output = Pat;
67
68 fn index(&self, pat: PatId) -> &Pat {
69 &self.pats[pat]
70 }
71}
72
73impl BodySyntaxMapping {
74 pub fn expr_syntax(&self, expr: ExprId) -> Option<LocalSyntaxPtr> {
75 self.expr_syntax_mapping_back.get(&expr).cloned()
76 }
77 pub fn syntax_expr(&self, ptr: LocalSyntaxPtr) -> Option<ExprId> {
78 self.expr_syntax_mapping.get(&ptr).cloned()
79 }
80 pub fn pat_syntax(&self, pat: PatId) -> Option<LocalSyntaxPtr> {
81 self.pat_syntax_mapping_back.get(&pat).cloned()
82 }
83 pub fn syntax_pat(&self, ptr: LocalSyntaxPtr) -> Option<PatId> {
84 self.pat_syntax_mapping.get(&ptr).cloned()
85 }
86
87 pub fn body(&self) -> &Arc<Body> {
88 &self.body
89 }
90}
91
92#[derive(Debug, Clone, Eq, PartialEq)]
93pub enum Expr {
94 /// This is produced if syntax tree does not have a required expression piece.
95 Missing,
96 Path(Path),
97 If {
98 condition: ExprId,
99 then_branch: ExprId,
100 else_branch: Option<ExprId>,
101 },
102 Block {
103 statements: Vec<Statement>,
104 tail: Option<ExprId>,
105 },
106 Loop {
107 body: ExprId,
108 },
109 While {
110 condition: ExprId,
111 body: ExprId,
112 },
113 For {
114 iterable: ExprId,
115 pat: PatId,
116 body: ExprId,
117 },
118 Call {
119 callee: ExprId,
120 args: Vec<ExprId>,
121 },
122 MethodCall {
123 receiver: ExprId,
124 method_name: Name,
125 args: Vec<ExprId>,
126 },
127 Match {
128 expr: ExprId,
129 arms: Vec<MatchArm>,
130 },
131 Continue,
132 Break {
133 expr: Option<ExprId>,
134 },
135 Return {
136 expr: Option<ExprId>,
137 },
138 StructLit {
139 path: Option<Path>,
140 fields: Vec<StructLitField>,
141 spread: Option<ExprId>,
142 },
143 Field {
144 expr: ExprId,
145 name: Name,
146 },
147 Try {
148 expr: ExprId,
149 },
150 Cast {
151 expr: ExprId,
152 type_ref: TypeRef,
153 },
154 Ref {
155 expr: ExprId,
156 mutability: Mutability,
157 },
158 UnaryOp {
159 expr: ExprId,
160 op: Option<UnaryOp>,
161 },
162 Lambda {
163 args: Vec<PatId>,
164 arg_types: Vec<Option<TypeRef>>,
165 body: ExprId,
166 },
167}
168
169pub type UnaryOp = ast::PrefixOp;
170
171#[derive(Debug, Clone, Eq, PartialEq)]
172pub struct MatchArm {
173 pub pats: Vec<PatId>,
174 // guard: Option<ExprId>, // TODO
175 pub expr: ExprId,
176}
177
178#[derive(Debug, Clone, Eq, PartialEq)]
179pub struct StructLitField {
180 pub name: Name,
181 pub expr: ExprId,
182}
183
184#[derive(Debug, Clone, Eq, PartialEq)]
185pub enum Statement {
186 Let {
187 pat: PatId,
188 type_ref: Option<TypeRef>,
189 initializer: Option<ExprId>,
190 },
191 Expr(ExprId),
192}
193
194impl Expr {
195 pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) {
196 match self {
197 Expr::Missing => {}
198 Expr::Path(_) => {}
199 Expr::If {
200 condition,
201 then_branch,
202 else_branch,
203 } => {
204 f(*condition);
205 f(*then_branch);
206 if let Some(else_branch) = else_branch {
207 f(*else_branch);
208 }
209 }
210 Expr::Block { statements, tail } => {
211 for stmt in statements {
212 match stmt {
213 Statement::Let { initializer, .. } => {
214 if let Some(expr) = initializer {
215 f(*expr);
216 }
217 }
218 Statement::Expr(e) => f(*e),
219 }
220 }
221 if let Some(expr) = tail {
222 f(*expr);
223 }
224 }
225 Expr::Loop { body } => f(*body),
226 Expr::While { condition, body } => {
227 f(*condition);
228 f(*body);
229 }
230 Expr::For { iterable, body, .. } => {
231 f(*iterable);
232 f(*body);
233 }
234 Expr::Call { callee, args } => {
235 f(*callee);
236 for arg in args {
237 f(*arg);
238 }
239 }
240 Expr::MethodCall { receiver, args, .. } => {
241 f(*receiver);
242 for arg in args {
243 f(*arg);
244 }
245 }
246 Expr::Match { expr, arms } => {
247 f(*expr);
248 for arm in arms {
249 f(arm.expr);
250 }
251 }
252 Expr::Continue => {}
253 Expr::Break { expr } | Expr::Return { expr } => {
254 if let Some(expr) = expr {
255 f(*expr);
256 }
257 }
258 Expr::StructLit { fields, spread, .. } => {
259 for field in fields {
260 f(field.expr);
261 }
262 if let Some(expr) = spread {
263 f(*expr);
264 }
265 }
266 Expr::Lambda { body, .. } => {
267 f(*body);
268 }
269 Expr::Field { expr, .. }
270 | Expr::Try { expr }
271 | Expr::Cast { expr, .. }
272 | Expr::Ref { expr, .. }
273 | Expr::UnaryOp { expr, .. } => {
274 f(*expr);
275 }
276 }
277 }
278}
279
280#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
281pub struct PatId(RawId);
282impl_arena_id!(PatId);
283
284#[derive(Debug, Clone, Eq, PartialEq)]
285pub enum Pat {
286 Missing,
287 Bind {
288 name: Name,
289 },
290 TupleStruct {
291 path: Option<Path>,
292 args: Vec<PatId>,
293 },
294}
295
296impl Pat {
297 pub fn walk_child_pats(&self, f: impl FnMut(PatId)) {
298 match self {
299 Pat::Missing | Pat::Bind { .. } => {}
300 Pat::TupleStruct { args, .. } => {
301 args.iter().map(|pat| *pat).for_each(f);
302 }
303 }
304 }
305}
306
307// Queries
308
309pub(crate) fn body_hir(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<Body>> {
310 Ok(Arc::clone(&body_syntax_mapping(db, def_id)?.body))
311}
312
313struct ExprCollector {
314 exprs: Arena<ExprId, Expr>,
315 pats: Arena<PatId, Pat>,
316 expr_syntax_mapping: FxHashMap<LocalSyntaxPtr, ExprId>,
317 expr_syntax_mapping_back: FxHashMap<ExprId, LocalSyntaxPtr>,
318 pat_syntax_mapping: FxHashMap<LocalSyntaxPtr, PatId>,
319 pat_syntax_mapping_back: FxHashMap<PatId, LocalSyntaxPtr>,
320}
321
322impl ExprCollector {
323 fn new() -> Self {
324 ExprCollector {
325 exprs: Arena::default(),
326 pats: Arena::default(),
327 expr_syntax_mapping: FxHashMap::default(),
328 expr_syntax_mapping_back: FxHashMap::default(),
329 pat_syntax_mapping: FxHashMap::default(),
330 pat_syntax_mapping_back: FxHashMap::default(),
331 }
332 }
333
334 fn alloc_expr(&mut self, expr: Expr, syntax_ptr: LocalSyntaxPtr) -> ExprId {
335 let id = self.exprs.alloc(expr);
336 self.expr_syntax_mapping.insert(syntax_ptr, id);
337 self.expr_syntax_mapping_back.insert(id, syntax_ptr);
338 id
339 }
340
341 fn alloc_pat(&mut self, pat: Pat, syntax_ptr: LocalSyntaxPtr) -> PatId {
342 let id = self.pats.alloc(pat);
343 self.pat_syntax_mapping.insert(syntax_ptr, id);
344 self.pat_syntax_mapping_back.insert(id, syntax_ptr);
345 id
346 }
347
348 fn empty_block(&mut self) -> ExprId {
349 let block = Expr::Block {
350 statements: Vec::new(),
351 tail: None,
352 };
353 self.exprs.alloc(block)
354 }
355
356 fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
357 let syntax_ptr = LocalSyntaxPtr::new(expr.syntax());
358 match expr {
359 ast::Expr::IfExpr(e) => {
360 if let Some(pat) = e.condition().and_then(|c| c.pat()) {
361 // if let -- desugar to match
362 let pat = self.collect_pat(pat);
363 let match_expr =
364 self.collect_expr_opt(e.condition().expect("checked above").expr());
365 let then_branch = self.collect_block_opt(e.then_branch());
366 let else_branch = e
367 .else_branch()
368 .map(|e| self.collect_block(e))
369 .unwrap_or_else(|| self.empty_block());
370 let placeholder_pat = self.pats.alloc(Pat::Missing);
371 let arms = vec![
372 MatchArm {
373 pats: vec![pat],
374 expr: then_branch,
375 },
376 MatchArm {
377 pats: vec![placeholder_pat],
378 expr: else_branch,
379 },
380 ];
381 self.alloc_expr(
382 Expr::Match {
383 expr: match_expr,
384 arms,
385 },
386 syntax_ptr,
387 )
388 } else {
389 let condition = self.collect_expr_opt(e.condition().and_then(|c| c.expr()));
390 let then_branch = self.collect_block_opt(e.then_branch());
391 let else_branch = e.else_branch().map(|e| self.collect_block(e));
392 self.alloc_expr(
393 Expr::If {
394 condition,
395 then_branch,
396 else_branch,
397 },
398 syntax_ptr,
399 )
400 }
401 }
402 ast::Expr::BlockExpr(e) => self.collect_block_opt(e.block()),
403 ast::Expr::LoopExpr(e) => {
404 let body = self.collect_block_opt(e.loop_body());
405 self.alloc_expr(Expr::Loop { body }, syntax_ptr)
406 }
407 ast::Expr::WhileExpr(e) => {
408 let condition = if let Some(condition) = e.condition() {
409 if condition.pat().is_none() {
410 self.collect_expr_opt(condition.expr())
411 } else {
412 // TODO handle while let
413 return self.alloc_expr(Expr::Missing, syntax_ptr);
414 }
415 } else {
416 self.exprs.alloc(Expr::Missing)
417 };
418 let body = self.collect_block_opt(e.loop_body());
419 self.alloc_expr(Expr::While { condition, body }, syntax_ptr)
420 }
421 ast::Expr::ForExpr(e) => {
422 let iterable = self.collect_expr_opt(e.iterable());
423 let pat = self.collect_pat_opt(e.pat());
424 let body = self.collect_block_opt(e.loop_body());
425 self.alloc_expr(
426 Expr::For {
427 iterable,
428 pat,
429 body,
430 },
431 syntax_ptr,
432 )
433 }
434 ast::Expr::CallExpr(e) => {
435 let callee = self.collect_expr_opt(e.expr());
436 let args = if let Some(arg_list) = e.arg_list() {
437 arg_list.args().map(|e| self.collect_expr(e)).collect()
438 } else {
439 Vec::new()
440 };
441 self.alloc_expr(Expr::Call { callee, args }, syntax_ptr)
442 }
443 ast::Expr::MethodCallExpr(e) => {
444 let receiver = self.collect_expr_opt(e.expr());
445 let args = if let Some(arg_list) = e.arg_list() {
446 arg_list.args().map(|e| self.collect_expr(e)).collect()
447 } else {
448 Vec::new()
449 };
450 let method_name = e
451 .name_ref()
452 .map(|nr| nr.as_name())
453 .unwrap_or_else(Name::missing);
454 self.alloc_expr(
455 Expr::MethodCall {
456 receiver,
457 method_name,
458 args,
459 },
460 syntax_ptr,
461 )
462 }
463 ast::Expr::MatchExpr(e) => {
464 let expr = self.collect_expr_opt(e.expr());
465 let arms = if let Some(match_arm_list) = e.match_arm_list() {
466 match_arm_list
467 .arms()
468 .map(|arm| MatchArm {
469 pats: arm.pats().map(|p| self.collect_pat(p)).collect(),
470 expr: self.collect_expr_opt(arm.expr()),
471 })
472 .collect()
473 } else {
474 Vec::new()
475 };
476 self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
477 }
478 ast::Expr::PathExpr(e) => {
479 let path = e
480 .path()
481 .and_then(Path::from_ast)
482 .map(Expr::Path)
483 .unwrap_or(Expr::Missing);
484 self.alloc_expr(path, syntax_ptr)
485 }
486 ast::Expr::ContinueExpr(_e) => {
487 // TODO: labels
488 self.alloc_expr(Expr::Continue, syntax_ptr)
489 }
490 ast::Expr::BreakExpr(e) => {
491 let expr = e.expr().map(|e| self.collect_expr(e));
492 self.alloc_expr(Expr::Break { expr }, syntax_ptr)
493 }
494 ast::Expr::ParenExpr(e) => {
495 let inner = self.collect_expr_opt(e.expr());
496 // make the paren expr point to the inner expression as well
497 self.expr_syntax_mapping.insert(syntax_ptr, inner);
498 inner
499 }
500 ast::Expr::ReturnExpr(e) => {
501 let expr = e.expr().map(|e| self.collect_expr(e));
502 self.alloc_expr(Expr::Return { expr }, syntax_ptr)
503 }
504 ast::Expr::StructLit(e) => {
505 let path = e.path().and_then(Path::from_ast);
506 let fields = if let Some(nfl) = e.named_field_list() {
507 nfl.fields()
508 .map(|field| StructLitField {
509 name: field
510 .name_ref()
511 .map(|nr| nr.as_name())
512 .unwrap_or_else(Name::missing),
513 expr: if let Some(e) = field.expr() {
514 self.collect_expr(e)
515 } else if let Some(nr) = field.name_ref() {
516 // field shorthand
517 let id = self.exprs.alloc(Expr::Path(Path::from_name_ref(nr)));
518 self.expr_syntax_mapping
519 .insert(LocalSyntaxPtr::new(nr.syntax()), id);
520 self.expr_syntax_mapping_back
521 .insert(id, LocalSyntaxPtr::new(nr.syntax()));
522 id
523 } else {
524 self.exprs.alloc(Expr::Missing)
525 },
526 })
527 .collect()
528 } else {
529 Vec::new()
530 };
531 let spread = e.spread().map(|s| self.collect_expr(s));
532 self.alloc_expr(
533 Expr::StructLit {
534 path,
535 fields,
536 spread,
537 },
538 syntax_ptr,
539 )
540 }
541 ast::Expr::FieldExpr(e) => {
542 let expr = self.collect_expr_opt(e.expr());
543 let name = e
544 .name_ref()
545 .map(|nr| nr.as_name())
546 .unwrap_or_else(Name::missing);
547 self.alloc_expr(Expr::Field { expr, name }, syntax_ptr)
548 }
549 ast::Expr::TryExpr(e) => {
550 let expr = self.collect_expr_opt(e.expr());
551 self.alloc_expr(Expr::Try { expr }, syntax_ptr)
552 }
553 ast::Expr::CastExpr(e) => {
554 let expr = self.collect_expr_opt(e.expr());
555 let type_ref = TypeRef::from_ast_opt(e.type_ref());
556 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
557 }
558 ast::Expr::RefExpr(e) => {
559 let expr = self.collect_expr_opt(e.expr());
560 let mutability = Mutability::from_mutable(e.is_mut());
561 self.alloc_expr(Expr::Ref { expr, mutability }, syntax_ptr)
562 }
563 ast::Expr::PrefixExpr(e) => {
564 let expr = self.collect_expr_opt(e.expr());
565 let op = e.op();
566 self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr)
567 }
568 ast::Expr::LambdaExpr(e) => {
569 let mut args = Vec::new();
570 let mut arg_types = Vec::new();
571 if let Some(pl) = e.param_list() {
572 for param in pl.params() {
573 let pat = self.collect_pat_opt(param.pat());
574 let type_ref = param.type_ref().map(TypeRef::from_ast);
575 args.push(pat);
576 arg_types.push(type_ref);
577 }
578 }
579 let body = self.collect_expr_opt(e.body());
580 self.alloc_expr(
581 Expr::Lambda {
582 args,
583 arg_types,
584 body,
585 },
586 syntax_ptr,
587 )
588 }
589
590 // TODO implement HIR for these:
591 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
592 ast::Expr::IndexExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
593 ast::Expr::TupleExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
594 ast::Expr::ArrayExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
595 ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
596 ast::Expr::BinExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
597 ast::Expr::Literal(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
598 }
599 }
600
601 fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
602 if let Some(expr) = expr {
603 self.collect_expr(expr)
604 } else {
605 self.exprs.alloc(Expr::Missing)
606 }
607 }
608
609 fn collect_block(&mut self, block: ast::Block) -> ExprId {
610 let statements = block
611 .statements()
612 .map(|s| match s {
613 ast::Stmt::LetStmt(stmt) => {
614 let pat = self.collect_pat_opt(stmt.pat());
615 let type_ref = stmt.type_ref().map(TypeRef::from_ast);
616 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
617 Statement::Let {
618 pat,
619 type_ref,
620 initializer,
621 }
622 }
623 ast::Stmt::ExprStmt(stmt) => Statement::Expr(self.collect_expr_opt(stmt.expr())),
624 })
625 .collect();
626 let tail = block.expr().map(|e| self.collect_expr(e));
627 self.alloc_expr(
628 Expr::Block { statements, tail },
629 LocalSyntaxPtr::new(block.syntax()),
630 )
631 }
632
633 fn collect_block_opt(&mut self, block: Option<ast::Block>) -> ExprId {
634 if let Some(block) = block {
635 self.collect_block(block)
636 } else {
637 self.exprs.alloc(Expr::Missing)
638 }
639 }
640
641 fn collect_pat(&mut self, pat: ast::Pat) -> PatId {
642 let syntax_ptr = LocalSyntaxPtr::new(pat.syntax());
643 match pat {
644 ast::Pat::BindPat(bp) => {
645 let name = bp
646 .name()
647 .map(|nr| nr.as_name())
648 .unwrap_or_else(Name::missing);
649 self.alloc_pat(Pat::Bind { name }, syntax_ptr)
650 }
651 ast::Pat::TupleStructPat(p) => {
652 let path = p.path().and_then(Path::from_ast);
653 let args = p.args().map(|p| self.collect_pat(p)).collect();
654 self.alloc_pat(Pat::TupleStruct { path, args }, syntax_ptr)
655 }
656 _ => {
657 // TODO
658 self.alloc_pat(Pat::Missing, syntax_ptr)
659 }
660 }
661 }
662
663 fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId {
664 if let Some(pat) = pat {
665 self.collect_pat(pat)
666 } else {
667 self.pats.alloc(Pat::Missing)
668 }
669 }
670
671 fn into_body_syntax_mapping(self, args: Vec<PatId>, body_expr: ExprId) -> BodySyntaxMapping {
672 let body = Body {
673 exprs: self.exprs,
674 pats: self.pats,
675 args,
676 body_expr,
677 };
678 BodySyntaxMapping {
679 body: Arc::new(body),
680 expr_syntax_mapping: self.expr_syntax_mapping,
681 expr_syntax_mapping_back: self.expr_syntax_mapping_back,
682 pat_syntax_mapping: self.pat_syntax_mapping,
683 pat_syntax_mapping_back: self.pat_syntax_mapping_back,
684 }
685 }
686}
687
688pub(crate) fn collect_fn_body_syntax(node: ast::FnDef) -> BodySyntaxMapping {
689 let mut collector = ExprCollector::new();
690
691 let args = if let Some(param_list) = node.param_list() {
692 let mut args = Vec::new();
693
694 if let Some(self_param) = param_list.self_param() {
695 let self_param = LocalSyntaxPtr::new(
696 self_param
697 .self_kw()
698 .expect("self param without self keyword")
699 .syntax(),
700 );
701 let arg = collector.alloc_pat(
702 Pat::Bind {
703 name: Name::self_param(),
704 },
705 self_param,
706 );
707 args.push(arg);
708 }
709
710 for param in param_list.params() {
711 let pat = if let Some(pat) = param.pat() {
712 pat
713 } else {
714 continue;
715 };
716 args.push(collector.collect_pat(pat));
717 }
718 args
719 } else {
720 Vec::new()
721 };
722
723 let body = collector.collect_block_opt(node.body());
724 collector.into_body_syntax_mapping(args, body)
725}
726
727pub(crate) fn body_syntax_mapping(
728 db: &impl HirDatabase,
729 def_id: DefId,
730) -> Cancelable<Arc<BodySyntaxMapping>> {
731 let def = def_id.resolve(db)?;
732
733 let body_syntax_mapping = match def {
734 Def::Function(f) => {
735 let node = f.syntax(db);
736 let node = node.borrowed();
737
738 collect_fn_body_syntax(node)
739 }
740 // TODO: consts, etc.
741 _ => panic!("Trying to get body for item type without body"),
742 };
743
744 Ok(Arc::new(body_syntax_mapping))
745}
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
14use crate::{DefId, DefKind, HirDatabase, ty::InferenceResult, Module, Crate, impl_block::ImplBlock}; 14use crate::{DefId, DefKind, HirDatabase, ty::InferenceResult, Module, Crate, impl_block::ImplBlock, expr::{Body, BodySyntaxMapping}, type_ref::{TypeRef, Mutability}, Name};
15 15
16pub use self::scope::FnScopes; 16pub use self::scope::{FnScopes, ScopesWithSyntaxMapping};
17 17
18#[derive(Debug, Clone, PartialEq, Eq)] 18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct Function { 19pub 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)]
85pub struct FnSignature {
86 args: Vec<TypeRef>,
87 ret_type: TypeRef,
88}
89
90impl 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
100pub(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)]
67pub struct FnSignatureInfo { 138pub 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 @@
1use std::sync::Arc;
2
1use rustc_hash::{FxHashMap, FxHashSet}; 3use rustc_hash::{FxHashMap, FxHashSet};
2 4
3use ra_syntax::{ 5use 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};
8use ra_arena::{Arena, RawId, impl_arena_id}; 10use ra_arena::{Arena, RawId, impl_arena_id};
9use ra_db::LocalSyntaxPtr; 11use ra_db::LocalSyntaxPtr;
10 12
11use crate::{Name, AsName}; 13use 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)]
14pub struct ScopeId(RawId); 16pub struct ScopeId(RawId);
@@ -16,15 +18,15 @@ impl_arena_id!(ScopeId);
16 18
17#[derive(Debug, PartialEq, Eq)] 19#[derive(Debug, PartialEq, Eq)]
18pub struct FnScopes { 20pub 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)]
25pub struct ScopeEntry { 27pub 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
36impl FnScopes { 38impl 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)]
109pub struct ScopesWithSyntaxMapping {
110 pub syntax_mapping: Arc<BodySyntaxMapping>,
111 pub scopes: Arc<FnScopes>,
112}
113
114#[derive(Debug, Clone, PartialEq, Eq)]
115pub struct ScopeEntryWithSyntax {
116 name: Name,
117 ptr: LocalSyntaxPtr,
118}
119
120impl ScopeEntryWithSyntax {
121 pub fn name(&self) -> &Name {
122 &self.name
123 }
124 pub fn ptr(&self) -> LocalSyntaxPtr {
125 self.ptr
126 }
127}
128
129impl 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
173impl ScopeEntry { 224impl 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
190fn compute_block_scopes(block: ast::Block, scopes: &mut FnScopes, mut scope: ScopeId) { 233fn 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
219fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) { 263fn 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;
32mod type_ref; 32mod type_ref;
33mod ty; 33mod ty;
34mod impl_block; 34mod impl_block;
35mod expr;
35 36
36use crate::{ 37use 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
92impl From<Name> for Path {
93 fn from(name: Name) -> Path {
94 Path {
95 kind: PathKind::Plain,
96 segments: vec![name],
97 }
98 }
99}
100
87fn expand_use_tree( 101fn 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::{
11use ra_db::{SourceRootId, Cancelable,}; 11use ra_db::{SourceRootId, Cancelable,};
12 12
13use crate::{ 13use 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
26pub(super) fn fn_scopes(db: &impl HirDatabase, def_id: DefId) -> Arc<FnScopes> { 26pub(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
33pub(super) fn struct_data(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<StructData>> { 32pub(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
90pub 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
90pub fn function_from_source( 102pub 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
33use crate::{ 33use 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)]
516struct InferenceContext<'a, D: HirDatabase> { 517struct 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> {
529impl<'a, D: HirDatabase> InferenceContext<'a, D> { 530impl<'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
1017pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceResult>> { 1010pub 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 @@
1use std::sync::Arc;
1use std::fmt::Write; 2use std::fmt::Write;
2use std::path::{PathBuf, Path}; 3use std::path::{PathBuf, Path};
3use std::fs; 4use std::fs;
4 5
6use salsa::Database;
7
5use ra_db::{SyntaxDatabase}; 8use ra_db::{SyntaxDatabase};
6use ra_syntax::ast::{self, AstNode}; 9use ra_syntax::ast::{self, AstNode};
7use test_utils::{project_dir, assert_eq_text, read_text}; 10use test_utils::{project_dir, assert_eq_text, read_text};
@@ -217,3 +220,44 @@ fn ellipsize(mut text: String, max_len: usize) -> String {
217fn test_data_dir() -> PathBuf { 220fn 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
226fn 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}
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 7df6a9c46..24f72393a 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -378,7 +378,11 @@ impl<R: TreeRoot<RaTypes>> BreakExprNode<R> {
378} 378}
379 379
380 380
381impl<'a> BreakExpr<'a> {} 381impl<'a> BreakExpr<'a> {
382 pub fn expr(self) -> Option<Expr<'a>> {
383 super::child_opt(self)
384 }
385}
382 386
383// Byte 387// Byte
384#[derive(Debug, Clone, Copy,)] 388#[derive(Debug, Clone, Copy,)]
@@ -923,12 +927,7 @@ pub enum Expr<'a> {
923 BlockExpr(BlockExpr<'a>), 927 BlockExpr(BlockExpr<'a>),
924 ReturnExpr(ReturnExpr<'a>), 928 ReturnExpr(ReturnExpr<'a>),
925 MatchExpr(MatchExpr<'a>), 929 MatchExpr(MatchExpr<'a>),
926 MatchArmList(MatchArmList<'a>),
927 MatchArm(MatchArm<'a>),
928 MatchGuard(MatchGuard<'a>),
929 StructLit(StructLit<'a>), 930 StructLit(StructLit<'a>),
930 NamedFieldList(NamedFieldList<'a>),
931 NamedField(NamedField<'a>),
932 CallExpr(CallExpr<'a>), 931 CallExpr(CallExpr<'a>),
933 IndexExpr(IndexExpr<'a>), 932 IndexExpr(IndexExpr<'a>),
934 MethodCallExpr(MethodCallExpr<'a>), 933 MethodCallExpr(MethodCallExpr<'a>),
@@ -960,12 +959,7 @@ impl<'a> AstNode<'a> for Expr<'a> {
960 BLOCK_EXPR => Some(Expr::BlockExpr(BlockExpr { syntax })), 959 BLOCK_EXPR => Some(Expr::BlockExpr(BlockExpr { syntax })),
961 RETURN_EXPR => Some(Expr::ReturnExpr(ReturnExpr { syntax })), 960 RETURN_EXPR => Some(Expr::ReturnExpr(ReturnExpr { syntax })),
962 MATCH_EXPR => Some(Expr::MatchExpr(MatchExpr { syntax })), 961 MATCH_EXPR => Some(Expr::MatchExpr(MatchExpr { syntax })),
963 MATCH_ARM_LIST => Some(Expr::MatchArmList(MatchArmList { syntax })),
964 MATCH_ARM => Some(Expr::MatchArm(MatchArm { syntax })),
965 MATCH_GUARD => Some(Expr::MatchGuard(MatchGuard { syntax })),
966 STRUCT_LIT => Some(Expr::StructLit(StructLit { syntax })), 962 STRUCT_LIT => Some(Expr::StructLit(StructLit { syntax })),
967 NAMED_FIELD_LIST => Some(Expr::NamedFieldList(NamedFieldList { syntax })),
968 NAMED_FIELD => Some(Expr::NamedField(NamedField { syntax })),
969 CALL_EXPR => Some(Expr::CallExpr(CallExpr { syntax })), 963 CALL_EXPR => Some(Expr::CallExpr(CallExpr { syntax })),
970 INDEX_EXPR => Some(Expr::IndexExpr(IndexExpr { syntax })), 964 INDEX_EXPR => Some(Expr::IndexExpr(IndexExpr { syntax })),
971 METHOD_CALL_EXPR => Some(Expr::MethodCallExpr(MethodCallExpr { syntax })), 965 METHOD_CALL_EXPR => Some(Expr::MethodCallExpr(MethodCallExpr { syntax })),
@@ -997,12 +991,7 @@ impl<'a> AstNode<'a> for Expr<'a> {
997 Expr::BlockExpr(inner) => inner.syntax(), 991 Expr::BlockExpr(inner) => inner.syntax(),
998 Expr::ReturnExpr(inner) => inner.syntax(), 992 Expr::ReturnExpr(inner) => inner.syntax(),
999 Expr::MatchExpr(inner) => inner.syntax(), 993 Expr::MatchExpr(inner) => inner.syntax(),
1000 Expr::MatchArmList(inner) => inner.syntax(),
1001 Expr::MatchArm(inner) => inner.syntax(),
1002 Expr::MatchGuard(inner) => inner.syntax(),
1003 Expr::StructLit(inner) => inner.syntax(), 994 Expr::StructLit(inner) => inner.syntax(),
1004 Expr::NamedFieldList(inner) => inner.syntax(),
1005 Expr::NamedField(inner) => inner.syntax(),
1006 Expr::CallExpr(inner) => inner.syntax(), 995 Expr::CallExpr(inner) => inner.syntax(),
1007 Expr::IndexExpr(inner) => inner.syntax(), 996 Expr::IndexExpr(inner) => inner.syntax(),
1008 Expr::MethodCallExpr(inner) => inner.syntax(), 997 Expr::MethodCallExpr(inner) => inner.syntax(),
@@ -3880,6 +3869,10 @@ impl<'a> StructLit<'a> {
3880 pub fn named_field_list(self) -> Option<NamedFieldList<'a>> { 3869 pub fn named_field_list(self) -> Option<NamedFieldList<'a>> {
3881 super::child_opt(self) 3870 super::child_opt(self)
3882 } 3871 }
3872
3873 pub fn spread(self) -> Option<Expr<'a>> {
3874 super::child_opt(self)
3875 }
3883} 3876}
3884 3877
3885// StructPat 3878// StructPat
@@ -4147,7 +4140,15 @@ impl<R: TreeRoot<RaTypes>> TupleStructPatNode<R> {
4147} 4140}
4148 4141
4149 4142
4150impl<'a> TupleStructPat<'a> {} 4143impl<'a> TupleStructPat<'a> {
4144 pub fn args(self) -> impl Iterator<Item = Pat<'a>> + 'a {
4145 super::children(self)
4146 }
4147
4148 pub fn path(self) -> Option<Path<'a>> {
4149 super::child_opt(self)
4150 }
4151}
4151 4152
4152// TupleType 4153// TupleType
4153#[derive(Debug, Clone, Copy,)] 4154#[derive(Debug, Clone, Copy,)]
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index c55e9e07a..3c640ed47 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -384,7 +384,7 @@ Grammar(
384 options: [ "Condition" ] 384 options: [ "Condition" ]
385 ), 385 ),
386 "ContinueExpr": (), 386 "ContinueExpr": (),
387 "BreakExpr": (), 387 "BreakExpr": (options: ["Expr"]),
388 "Label": (), 388 "Label": (),
389 "BlockExpr": ( 389 "BlockExpr": (
390 options: [ "Block" ] 390 options: [ "Block" ]
@@ -404,7 +404,7 @@ Grammar(
404 collections: [ [ "pats", "Pat" ] ] 404 collections: [ [ "pats", "Pat" ] ]
405 ), 405 ),
406 "MatchGuard": (), 406 "MatchGuard": (),
407 "StructLit": (options: ["Path", "NamedFieldList"]), 407 "StructLit": (options: ["Path", "NamedFieldList", ["spread", "Expr"]]),
408 "NamedFieldList": (collections: [ ["fields", "NamedField"] ]), 408 "NamedFieldList": (collections: [ ["fields", "NamedField"] ]),
409 "NamedField": (options: ["NameRef", "Expr"]), 409 "NamedField": (options: ["NameRef", "Expr"]),
410 "CallExpr": ( 410 "CallExpr": (
@@ -446,12 +446,7 @@ Grammar(
446 "BlockExpr", 446 "BlockExpr",
447 "ReturnExpr", 447 "ReturnExpr",
448 "MatchExpr", 448 "MatchExpr",
449 "MatchArmList",
450 "MatchArm",
451 "MatchGuard",
452 "StructLit", 449 "StructLit",
453 "NamedFieldList",
454 "NamedField",
455 "CallExpr", 450 "CallExpr",
456 "IndexExpr", 451 "IndexExpr",
457 "MethodCallExpr", 452 "MethodCallExpr",
@@ -472,7 +467,10 @@ Grammar(
472 "PathPat": (), 467 "PathPat": (),
473 "StructPat": (), 468 "StructPat": (),
474 "FieldPatList": (), 469 "FieldPatList": (),
475 "TupleStructPat": (), 470 "TupleStructPat": (
471 options: ["Path"],
472 collections: [["args", "Pat"]],
473 ),
476 "TuplePat": (), 474 "TuplePat": (),
477 "SlicePat": (), 475 "SlicePat": (),
478 "RangePat": (), 476 "RangePat": (),