diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-01 22:37:59 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-01 22:37:59 +0000 |
commit | 4447019f4b5f24728bb7b91b161755ddb373c74c (patch) | |
tree | c53ff3531cbbad182e821eb92fa9ad201d2bff0c /crates | |
parent | 2b5c226e86892113bcab478cdf4c9adaf1e7b2f6 (diff) | |
parent | c5852f422ff45adaa21815c1a15e03b067a56a82 (diff) |
Merge #693
693: Name resolution refactoring r=matklad a=flodiebold
This is still very WIP, but it's becoming quite big and I want to make sure this isn't going in a completely bad direction :sweat_smile:. I'm not really happy with how the path resolution looks, and I'm not sure `PerNs<Resolution>` is the best return type -- there are 'this cannot happen in the (types/values) namespace' cases everywhere. I also want to unify the `resolver` and `nameres` namespaces once I'm done switching everything to `Resolver`. Also, `Resolver` only has a lifetime because it needs to have a reference to the `ItemMap` during import resolution :confused:
The differences in the completion snapshots are almost completely just ordering (except it completes `Self` as well now), so I changed it to sort the completions before snapshotting.
Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates')
26 files changed, 906 insertions, 421 deletions
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs index 71123a698..92ab0f692 100644 --- a/crates/ra_hir/src/code_model_api.rs +++ b/crates/ra_hir/src/code_model_api.rs | |||
@@ -5,18 +5,19 @@ use ra_db::{CrateId, FileId}; | |||
5 | use ra_syntax::{ast::self, TreeArc, SyntaxNode}; | 5 | use ra_syntax::{ast::self, TreeArc, SyntaxNode}; |
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
8 | Name, Path, PerNs, ScopesWithSyntaxMapping, Ty, HirFileId, | 8 | Name, ScopesWithSyntaxMapping, Ty, HirFileId, |
9 | type_ref::TypeRef, | 9 | type_ref::TypeRef, |
10 | nameres::{ModuleScope, lower::ImportId}, | 10 | nameres::{ModuleScope, lower::ImportId}, |
11 | HirDatabase, PersistentHirDatabase, | 11 | HirDatabase, PersistentHirDatabase, |
12 | expr::BodySyntaxMapping, | 12 | expr::{Body, BodySyntaxMapping}, |
13 | ty::{InferenceResult}, | 13 | ty::InferenceResult, |
14 | adt::{EnumVariantId, StructFieldId, VariantDef}, | 14 | adt::{EnumVariantId, StructFieldId, VariantDef}, |
15 | generics::GenericParams, | 15 | generics::GenericParams, |
16 | docs::{Documentation, Docs, docs_from_ast}, | 16 | docs::{Documentation, Docs, docs_from_ast}, |
17 | module_tree::ModuleId, | 17 | module_tree::ModuleId, |
18 | ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeId}, | 18 | ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeId}, |
19 | impl_block::ImplId, | 19 | impl_block::ImplId, |
20 | resolve::Resolver, | ||
20 | }; | 21 | }; |
21 | 22 | ||
22 | /// hir::Crate describes a single crate. It's the main interface with which | 23 | /// hir::Crate describes a single crate. It's the main interface with which |
@@ -174,13 +175,14 @@ impl Module { | |||
174 | db.item_map(self.krate)[self.module_id].clone() | 175 | db.item_map(self.krate)[self.module_id].clone() |
175 | } | 176 | } |
176 | 177 | ||
177 | pub fn resolve_path(&self, db: &impl PersistentHirDatabase, path: &Path) -> PerNs<ModuleDef> { | ||
178 | db.item_map(self.krate).resolve_path(db, *self, path) | ||
179 | } | ||
180 | |||
181 | pub fn problems(&self, db: &impl HirDatabase) -> Vec<(TreeArc<SyntaxNode>, Problem)> { | 178 | pub fn problems(&self, db: &impl HirDatabase) -> Vec<(TreeArc<SyntaxNode>, Problem)> { |
182 | self.problems_impl(db) | 179 | self.problems_impl(db) |
183 | } | 180 | } |
181 | |||
182 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | ||
183 | let item_map = db.item_map(self.krate); | ||
184 | Resolver::default().push_module_scope(item_map, *self) | ||
185 | } | ||
184 | } | 186 | } |
185 | 187 | ||
186 | impl Docs for Module { | 188 | impl Docs for Module { |
@@ -282,6 +284,21 @@ impl Struct { | |||
282 | pub fn ty(&self, db: &impl HirDatabase) -> Ty { | 284 | pub fn ty(&self, db: &impl HirDatabase) -> Ty { |
283 | db.type_for_def((*self).into()) | 285 | db.type_for_def((*self).into()) |
284 | } | 286 | } |
287 | |||
288 | // TODO move to a more general type | ||
289 | /// Builds a resolver for type references inside this struct. | ||
290 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | ||
291 | // take the outer scope... | ||
292 | let r = self.module(db).resolver(db); | ||
293 | // ...and add generic params, if present | ||
294 | let p = self.generic_params(db); | ||
295 | let r = if !p.params.is_empty() { | ||
296 | r.push_generic_params_scope(p) | ||
297 | } else { | ||
298 | r | ||
299 | }; | ||
300 | r | ||
301 | } | ||
285 | } | 302 | } |
286 | 303 | ||
287 | impl Docs for Struct { | 304 | impl Docs for Struct { |
@@ -331,6 +348,21 @@ impl Enum { | |||
331 | pub fn ty(&self, db: &impl HirDatabase) -> Ty { | 348 | pub fn ty(&self, db: &impl HirDatabase) -> Ty { |
332 | db.type_for_def((*self).into()) | 349 | db.type_for_def((*self).into()) |
333 | } | 350 | } |
351 | |||
352 | // TODO move to a more general type | ||
353 | /// Builds a resolver for type references inside this struct. | ||
354 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | ||
355 | // take the outer scope... | ||
356 | let r = self.module(db).resolver(db); | ||
357 | // ...and add generic params, if present | ||
358 | let p = self.generic_params(db); | ||
359 | let r = if !p.params.is_empty() { | ||
360 | r.push_generic_params_scope(p) | ||
361 | } else { | ||
362 | r | ||
363 | }; | ||
364 | r | ||
365 | } | ||
334 | } | 366 | } |
335 | 367 | ||
336 | impl Docs for Enum { | 368 | impl Docs for Enum { |
@@ -449,6 +481,10 @@ impl Function { | |||
449 | db.body_syntax_mapping(*self) | 481 | db.body_syntax_mapping(*self) |
450 | } | 482 | } |
451 | 483 | ||
484 | pub fn body(&self, db: &impl HirDatabase) -> Arc<Body> { | ||
485 | db.body_hir(*self) | ||
486 | } | ||
487 | |||
452 | pub fn scopes(&self, db: &impl HirDatabase) -> ScopesWithSyntaxMapping { | 488 | pub fn scopes(&self, db: &impl HirDatabase) -> ScopesWithSyntaxMapping { |
453 | let scopes = db.expr_scopes(*self); | 489 | let scopes = db.expr_scopes(*self); |
454 | let syntax_mapping = db.body_syntax_mapping(*self); | 490 | let syntax_mapping = db.body_syntax_mapping(*self); |
@@ -469,6 +505,24 @@ impl Function { | |||
469 | pub fn generic_params(&self, db: &impl PersistentHirDatabase) -> Arc<GenericParams> { | 505 | pub fn generic_params(&self, db: &impl PersistentHirDatabase) -> Arc<GenericParams> { |
470 | db.generic_params((*self).into()) | 506 | db.generic_params((*self).into()) |
471 | } | 507 | } |
508 | |||
509 | // TODO move to a more general type for 'body-having' items | ||
510 | /// Builds a resolver for code inside this item. | ||
511 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | ||
512 | // take the outer scope... | ||
513 | let r = self | ||
514 | .impl_block(db) | ||
515 | .map(|ib| ib.resolver(db)) | ||
516 | .unwrap_or_else(|| self.module(db).resolver(db)); | ||
517 | // ...and add generic params, if present | ||
518 | let p = self.generic_params(db); | ||
519 | let r = if !p.params.is_empty() { | ||
520 | r.push_generic_params_scope(p) | ||
521 | } else { | ||
522 | r | ||
523 | }; | ||
524 | r | ||
525 | } | ||
472 | } | 526 | } |
473 | 527 | ||
474 | impl Docs for Function { | 528 | impl Docs for Function { |
diff --git a/crates/ra_hir/src/code_model_impl/function.rs b/crates/ra_hir/src/code_model_impl/function.rs index 5b0b31b1d..8326c02c7 100644 --- a/crates/ra_hir/src/code_model_impl/function.rs +++ b/crates/ra_hir/src/code_model_impl/function.rs | |||
@@ -5,14 +5,12 @@ use ra_syntax::ast::{self, NameOwner}; | |||
5 | use crate::{ | 5 | use crate::{ |
6 | HirDatabase, Name, AsName, Function, FnSignature, | 6 | HirDatabase, Name, AsName, Function, FnSignature, |
7 | type_ref::{TypeRef, Mutability}, | 7 | type_ref::{TypeRef, Mutability}, |
8 | expr::Body, PersistentHirDatabase, | 8 | PersistentHirDatabase, |
9 | impl_block::ImplBlock, | 9 | impl_block::ImplBlock, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | impl Function { | 12 | impl Function { |
13 | pub(crate) fn body(&self, db: &impl HirDatabase) -> Arc<Body> { | 13 | // TODO impl_block should probably also be part of the code model API? |
14 | db.body_hir(*self) | ||
15 | } | ||
16 | 14 | ||
17 | /// The containing impl block, if this is a method. | 15 | /// The containing impl block, if this is a method. |
18 | pub(crate) fn impl_block(&self, db: &impl HirDatabase) -> Option<ImplBlock> { | 16 | pub(crate) fn impl_block(&self, db: &impl HirDatabase) -> Option<ImplBlock> { |
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index f4a950418..f9f702ae2 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs | |||
@@ -10,15 +10,15 @@ use ra_syntax::{ | |||
10 | }; | 10 | }; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | Path, Name, Function, | 13 | Path, Name, HirDatabase, Function, Resolver, |
14 | name::AsName, HirDatabase, | 14 | name::AsName, |
15 | type_ref::{Mutability, TypeRef}, | 15 | type_ref::{Mutability, TypeRef}, |
16 | }; | 16 | }; |
17 | use crate::ty::primitive::{UintTy, UncertainIntTy, UncertainFloatTy}; | 17 | use crate::ty::primitive::{UintTy, UncertainIntTy, UncertainFloatTy}; |
18 | 18 | ||
19 | pub use self::scope::{ExprScopes, ScopesWithSyntaxMapping, ScopeEntryWithSyntax}; | 19 | pub use self::scope::{ExprScopes, ScopesWithSyntaxMapping, ScopeEntryWithSyntax}; |
20 | 20 | ||
21 | mod scope; | 21 | pub(crate) mod scope; |
22 | 22 | ||
23 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | 23 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
24 | pub struct ExprId(RawId); | 24 | pub struct ExprId(RawId); |
@@ -27,6 +27,9 @@ impl_arena_id!(ExprId); | |||
27 | /// The body of an item (function, const etc.). | 27 | /// The body of an item (function, const etc.). |
28 | #[derive(Debug, Eq, PartialEq)] | 28 | #[derive(Debug, Eq, PartialEq)] |
29 | pub struct Body { | 29 | pub struct Body { |
30 | // TODO: this should be more general, consts & statics also have bodies | ||
31 | /// The Function of the item this body belongs to | ||
32 | owner: Function, | ||
30 | exprs: Arena<ExprId, Expr>, | 33 | exprs: Arena<ExprId, Expr>, |
31 | pats: Arena<PatId, Pat>, | 34 | pats: Arena<PatId, Pat>, |
32 | /// The patterns for the function's parameters. While the parameter types are | 35 | /// The patterns for the function's parameters. While the parameter types are |
@@ -62,6 +65,34 @@ impl Body { | |||
62 | pub fn body_expr(&self) -> ExprId { | 65 | pub fn body_expr(&self) -> ExprId { |
63 | self.body_expr | 66 | self.body_expr |
64 | } | 67 | } |
68 | |||
69 | pub fn owner(&self) -> Function { | ||
70 | self.owner | ||
71 | } | ||
72 | |||
73 | pub fn syntax_mapping(&self, db: &impl HirDatabase) -> Arc<BodySyntaxMapping> { | ||
74 | db.body_syntax_mapping(self.owner) | ||
75 | } | ||
76 | } | ||
77 | |||
78 | // needs arbitrary_self_types to be a method... or maybe move to the def? | ||
79 | pub fn resolver_for_expr(body: Arc<Body>, db: &impl HirDatabase, expr_id: ExprId) -> Resolver { | ||
80 | let scopes = db.expr_scopes(body.owner); | ||
81 | resolver_for_scope(body, db, scopes.scope_for(expr_id)) | ||
82 | } | ||
83 | |||
84 | pub fn resolver_for_scope( | ||
85 | body: Arc<Body>, | ||
86 | db: &impl HirDatabase, | ||
87 | scope_id: Option<scope::ScopeId>, | ||
88 | ) -> Resolver { | ||
89 | let mut r = body.owner.resolver(db); | ||
90 | let scopes = db.expr_scopes(body.owner); | ||
91 | let scope_chain = scopes.scope_chain_for(scope_id).collect::<Vec<_>>(); | ||
92 | for scope in scope_chain.into_iter().rev() { | ||
93 | r = r.push_expr_scope(Arc::clone(&scopes), scope); | ||
94 | } | ||
95 | r | ||
65 | } | 96 | } |
66 | 97 | ||
67 | impl Index<ExprId> for Body { | 98 | impl Index<ExprId> for Body { |
@@ -448,23 +479,29 @@ pub(crate) fn body_hir(db: &impl HirDatabase, func: Function) -> Arc<Body> { | |||
448 | } | 479 | } |
449 | 480 | ||
450 | struct ExprCollector { | 481 | struct ExprCollector { |
482 | owner: Function, | ||
451 | exprs: Arena<ExprId, Expr>, | 483 | exprs: Arena<ExprId, Expr>, |
452 | pats: Arena<PatId, Pat>, | 484 | pats: Arena<PatId, Pat>, |
453 | expr_syntax_mapping: FxHashMap<SyntaxNodePtr, ExprId>, | 485 | expr_syntax_mapping: FxHashMap<SyntaxNodePtr, ExprId>, |
454 | expr_syntax_mapping_back: ArenaMap<ExprId, SyntaxNodePtr>, | 486 | expr_syntax_mapping_back: ArenaMap<ExprId, SyntaxNodePtr>, |
455 | pat_syntax_mapping: FxHashMap<SyntaxNodePtr, PatId>, | 487 | pat_syntax_mapping: FxHashMap<SyntaxNodePtr, PatId>, |
456 | pat_syntax_mapping_back: ArenaMap<PatId, SyntaxNodePtr>, | 488 | pat_syntax_mapping_back: ArenaMap<PatId, SyntaxNodePtr>, |
489 | params: Vec<PatId>, | ||
490 | body_expr: Option<ExprId>, | ||
457 | } | 491 | } |
458 | 492 | ||
459 | impl ExprCollector { | 493 | impl ExprCollector { |
460 | fn new() -> Self { | 494 | fn new(owner: Function) -> Self { |
461 | ExprCollector { | 495 | ExprCollector { |
496 | owner, | ||
462 | exprs: Arena::default(), | 497 | exprs: Arena::default(), |
463 | pats: Arena::default(), | 498 | pats: Arena::default(), |
464 | expr_syntax_mapping: FxHashMap::default(), | 499 | expr_syntax_mapping: FxHashMap::default(), |
465 | expr_syntax_mapping_back: ArenaMap::default(), | 500 | expr_syntax_mapping_back: ArenaMap::default(), |
466 | pat_syntax_mapping: FxHashMap::default(), | 501 | pat_syntax_mapping: FxHashMap::default(), |
467 | pat_syntax_mapping_back: ArenaMap::default(), | 502 | pat_syntax_mapping_back: ArenaMap::default(), |
503 | params: Vec::new(), | ||
504 | body_expr: None, | ||
468 | } | 505 | } |
469 | } | 506 | } |
470 | 507 | ||
@@ -902,10 +939,7 @@ impl ExprCollector { | |||
902 | }); | 939 | }); |
903 | fields.extend(iter); | 940 | fields.extend(iter); |
904 | 941 | ||
905 | Pat::Struct { | 942 | Pat::Struct { path, args: fields } |
906 | path: path, | ||
907 | args: fields, | ||
908 | } | ||
909 | } | 943 | } |
910 | 944 | ||
911 | // TODO: implement | 945 | // TODO: implement |
@@ -923,12 +957,48 @@ impl ExprCollector { | |||
923 | } | 957 | } |
924 | } | 958 | } |
925 | 959 | ||
926 | fn into_body_syntax_mapping(self, params: Vec<PatId>, body_expr: ExprId) -> BodySyntaxMapping { | 960 | fn collect_fn_body(&mut self, node: &ast::FnDef) { |
961 | if let Some(param_list) = node.param_list() { | ||
962 | if let Some(self_param) = param_list.self_param() { | ||
963 | let self_param = SyntaxNodePtr::new( | ||
964 | self_param | ||
965 | .self_kw() | ||
966 | .expect("self param without self keyword") | ||
967 | .syntax(), | ||
968 | ); | ||
969 | let param_pat = self.alloc_pat( | ||
970 | Pat::Bind { | ||
971 | name: Name::self_param(), | ||
972 | mode: BindingAnnotation::Unannotated, | ||
973 | subpat: None, | ||
974 | }, | ||
975 | self_param, | ||
976 | ); | ||
977 | self.params.push(param_pat); | ||
978 | } | ||
979 | |||
980 | for param in param_list.params() { | ||
981 | let pat = if let Some(pat) = param.pat() { | ||
982 | pat | ||
983 | } else { | ||
984 | continue; | ||
985 | }; | ||
986 | let param_pat = self.collect_pat(pat); | ||
987 | self.params.push(param_pat); | ||
988 | } | ||
989 | }; | ||
990 | |||
991 | let body = self.collect_block_opt(node.body()); | ||
992 | self.body_expr = Some(body); | ||
993 | } | ||
994 | |||
995 | fn into_body_syntax_mapping(self) -> BodySyntaxMapping { | ||
927 | let body = Body { | 996 | let body = Body { |
997 | owner: self.owner, | ||
928 | exprs: self.exprs, | 998 | exprs: self.exprs, |
929 | pats: self.pats, | 999 | pats: self.pats, |
930 | params, | 1000 | params: self.params, |
931 | body_expr, | 1001 | body_expr: self.body_expr.expect("A body should have been collected"), |
932 | }; | 1002 | }; |
933 | BodySyntaxMapping { | 1003 | BodySyntaxMapping { |
934 | body: Arc::new(body), | 1004 | body: Arc::new(body), |
@@ -940,49 +1010,18 @@ impl ExprCollector { | |||
940 | } | 1010 | } |
941 | } | 1011 | } |
942 | 1012 | ||
943 | pub(crate) fn collect_fn_body_syntax(node: &ast::FnDef) -> BodySyntaxMapping { | 1013 | pub(crate) fn body_syntax_mapping(db: &impl HirDatabase, func: Function) -> Arc<BodySyntaxMapping> { |
944 | let mut collector = ExprCollector::new(); | 1014 | let mut collector = ExprCollector::new(func); |
945 | |||
946 | let params = if let Some(param_list) = node.param_list() { | ||
947 | let mut params = Vec::new(); | ||
948 | |||
949 | if let Some(self_param) = param_list.self_param() { | ||
950 | let self_param = SyntaxNodePtr::new( | ||
951 | self_param | ||
952 | .self_kw() | ||
953 | .expect("self param without self keyword") | ||
954 | .syntax(), | ||
955 | ); | ||
956 | let param = collector.alloc_pat( | ||
957 | Pat::Bind { | ||
958 | name: Name::self_param(), | ||
959 | mode: BindingAnnotation::Unannotated, | ||
960 | subpat: None, | ||
961 | }, | ||
962 | self_param, | ||
963 | ); | ||
964 | params.push(param); | ||
965 | } | ||
966 | 1015 | ||
967 | for param in param_list.params() { | 1016 | // TODO: consts, etc. |
968 | let pat = if let Some(pat) = param.pat() { | 1017 | collector.collect_fn_body(&func.source(db).1); |
969 | pat | ||
970 | } else { | ||
971 | continue; | ||
972 | }; | ||
973 | params.push(collector.collect_pat(pat)); | ||
974 | } | ||
975 | params | ||
976 | } else { | ||
977 | Vec::new() | ||
978 | }; | ||
979 | 1018 | ||
980 | let body = collector.collect_block_opt(node.body()); | 1019 | Arc::new(collector.into_body_syntax_mapping()) |
981 | collector.into_body_syntax_mapping(params, body) | ||
982 | } | 1020 | } |
983 | 1021 | ||
984 | pub(crate) fn body_syntax_mapping(db: &impl HirDatabase, func: Function) -> Arc<BodySyntaxMapping> { | 1022 | #[cfg(test)] |
985 | let (_, fn_def) = func.source(db); | 1023 | pub(crate) fn collect_fn_body_syntax(function: Function, node: &ast::FnDef) -> BodySyntaxMapping { |
986 | let body_syntax_mapping = collect_fn_body_syntax(&fn_def); | 1024 | let mut collector = ExprCollector::new(function); |
987 | Arc::new(body_syntax_mapping) | 1025 | collector.collect_fn_body(node); |
1026 | collector.into_body_syntax_mapping() | ||
988 | } | 1027 | } |
diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs index b7971088d..9202e3671 100644 --- a/crates/ra_hir/src/expr/scope.rs +++ b/crates/ra_hir/src/expr/scope.rs | |||
@@ -58,28 +58,19 @@ impl ExprScopes { | |||
58 | scopes | 58 | scopes |
59 | } | 59 | } |
60 | 60 | ||
61 | pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { | 61 | pub fn body(&self) -> Arc<Body> { |
62 | &self.scopes[scope].entries | 62 | self.body.clone() |
63 | } | 63 | } |
64 | 64 | ||
65 | pub fn scope_chain_for<'a>(&'a self, expr: ExprId) -> impl Iterator<Item = ScopeId> + 'a { | 65 | pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { |
66 | generate(self.scope_for(expr), move |&scope| { | 66 | &self.scopes[scope].entries |
67 | self.scopes[scope].parent | ||
68 | }) | ||
69 | } | 67 | } |
70 | 68 | ||
71 | pub fn resolve_local_name<'a>( | 69 | pub fn scope_chain_for<'a>( |
72 | &'a self, | 70 | &'a self, |
73 | context_expr: ExprId, | 71 | scope: Option<ScopeId>, |
74 | name: Name, | 72 | ) -> impl Iterator<Item = ScopeId> + 'a { |
75 | ) -> Option<&'a ScopeEntry> { | 73 | generate(scope, move |&scope| self.scopes[scope].parent) |
76 | let mut shadowed = FxHashSet::default(); | ||
77 | let ret = self | ||
78 | .scope_chain_for(context_expr) | ||
79 | .flat_map(|scope| self.entries(scope).iter()) | ||
80 | .filter(|entry| shadowed.insert(entry.name())) | ||
81 | .find(|entry| entry.name() == &name); | ||
82 | ret | ||
83 | } | 74 | } |
84 | 75 | ||
85 | fn root_scope(&mut self) -> ScopeId { | 76 | fn root_scope(&mut self) -> ScopeId { |
@@ -122,7 +113,7 @@ impl ExprScopes { | |||
122 | self.scope_for.insert(node, scope); | 113 | self.scope_for.insert(node, scope); |
123 | } | 114 | } |
124 | 115 | ||
125 | fn scope_for(&self, expr: ExprId) -> Option<ScopeId> { | 116 | pub fn scope_for(&self, expr: ExprId) -> Option<ScopeId> { |
126 | self.scope_for.get(&expr).map(|&scope| scope) | 117 | self.scope_for.get(&expr).map(|&scope| scope) |
127 | } | 118 | } |
128 | } | 119 | } |
@@ -150,18 +141,14 @@ impl ScopeEntryWithSyntax { | |||
150 | } | 141 | } |
151 | 142 | ||
152 | impl ScopesWithSyntaxMapping { | 143 | impl ScopesWithSyntaxMapping { |
153 | pub fn scope_chain<'a>(&'a self, node: &SyntaxNode) -> impl Iterator<Item = ScopeId> + 'a { | 144 | fn scope_chain<'a>(&'a self, node: &SyntaxNode) -> impl Iterator<Item = ScopeId> + 'a { |
154 | generate(self.scope_for(node), move |&scope| { | 145 | generate(self.scope_for(node), move |&scope| { |
155 | self.scopes.scopes[scope].parent | 146 | self.scopes.scopes[scope].parent |
156 | }) | 147 | }) |
157 | } | 148 | } |
158 | 149 | ||
159 | pub fn scope_chain_for_offset<'a>( | 150 | pub fn scope_for_offset<'a>(&'a self, offset: TextUnit) -> Option<ScopeId> { |
160 | &'a self, | 151 | self.scopes |
161 | offset: TextUnit, | ||
162 | ) -> impl Iterator<Item = ScopeId> + 'a { | ||
163 | let scope = self | ||
164 | .scopes | ||
165 | .scope_for | 152 | .scope_for |
166 | .iter() | 153 | .iter() |
167 | .filter_map(|(id, scope)| Some((self.syntax_mapping.expr_syntax(*id)?, scope))) | 154 | .filter_map(|(id, scope)| Some((self.syntax_mapping.expr_syntax(*id)?, scope))) |
@@ -172,13 +159,12 @@ impl ScopesWithSyntaxMapping { | |||
172 | ptr.range().len(), | 159 | ptr.range().len(), |
173 | ) | 160 | ) |
174 | }) | 161 | }) |
175 | .map(|(ptr, scope)| self.adjust(ptr, *scope, offset)); | 162 | .map(|(ptr, scope)| self.adjust(ptr, *scope, offset)) |
176 | |||
177 | generate(scope, move |&scope| self.scopes.scopes[scope].parent) | ||
178 | } | 163 | } |
179 | 164 | ||
180 | // XXX: during completion, cursor might be outside of any particular | 165 | // XXX: during completion, cursor might be outside of any particular |
181 | // expression. Try to figure out the correct scope... | 166 | // expression. Try to figure out the correct scope... |
167 | // TODO: move this to source binder? | ||
182 | fn adjust(&self, ptr: SyntaxNodePtr, original_scope: ScopeId, offset: TextUnit) -> ScopeId { | 168 | fn adjust(&self, ptr: SyntaxNodePtr, original_scope: ScopeId, offset: TextUnit) -> ScopeId { |
183 | let r = ptr.range(); | 169 | let r = ptr.range(); |
184 | let child_scopes = self | 170 | let child_scopes = self |
@@ -238,7 +224,7 @@ impl ScopesWithSyntaxMapping { | |||
238 | .collect() | 224 | .collect() |
239 | } | 225 | } |
240 | 226 | ||
241 | fn scope_for(&self, node: &SyntaxNode) -> Option<ScopeId> { | 227 | pub fn scope_for(&self, node: &SyntaxNode) -> Option<ScopeId> { |
242 | node.ancestors() | 228 | node.ancestors() |
243 | .map(SyntaxNodePtr::new) | 229 | .map(SyntaxNodePtr::new) |
244 | .filter_map(|ptr| self.syntax_mapping.syntax_expr(ptr)) | 230 | .filter_map(|ptr| self.syntax_mapping.syntax_expr(ptr)) |
@@ -336,6 +322,7 @@ pub struct ReferenceDescriptor { | |||
336 | mod tests { | 322 | mod tests { |
337 | use ra_syntax::{SourceFile, algo::find_node_at_offset}; | 323 | use ra_syntax::{SourceFile, algo::find_node_at_offset}; |
338 | use test_utils::{extract_offset, assert_eq_text}; | 324 | use test_utils::{extract_offset, assert_eq_text}; |
325 | use ra_arena::ArenaId; | ||
339 | 326 | ||
340 | use crate::expr; | 327 | use crate::expr; |
341 | 328 | ||
@@ -354,7 +341,10 @@ mod tests { | |||
354 | let file = SourceFile::parse(&code); | 341 | let file = SourceFile::parse(&code); |
355 | let marker: &ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); | 342 | let marker: &ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); |
356 | let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); | 343 | let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); |
357 | let body_hir = expr::collect_fn_body_syntax(fn_def); | 344 | let irrelevant_function = Function { |
345 | id: crate::ids::FunctionId::from_raw(0.into()), | ||
346 | }; | ||
347 | let body_hir = expr::collect_fn_body_syntax(irrelevant_function, fn_def); | ||
358 | let scopes = ExprScopes::new(Arc::clone(body_hir.body())); | 348 | let scopes = ExprScopes::new(Arc::clone(body_hir.body())); |
359 | let scopes = ScopesWithSyntaxMapping { | 349 | let scopes = ScopesWithSyntaxMapping { |
360 | scopes: Arc::new(scopes), | 350 | scopes: Arc::new(scopes), |
@@ -454,7 +444,10 @@ mod tests { | |||
454 | let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); | 444 | let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); |
455 | let name_ref: &ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); | 445 | let name_ref: &ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); |
456 | 446 | ||
457 | let body_hir = expr::collect_fn_body_syntax(fn_def); | 447 | let irrelevant_function = Function { |
448 | id: crate::ids::FunctionId::from_raw(0.into()), | ||
449 | }; | ||
450 | let body_hir = expr::collect_fn_body_syntax(irrelevant_function, fn_def); | ||
458 | let scopes = ExprScopes::new(Arc::clone(body_hir.body())); | 451 | let scopes = ExprScopes::new(Arc::clone(body_hir.body())); |
459 | let scopes = ScopesWithSyntaxMapping { | 452 | let scopes = ScopesWithSyntaxMapping { |
460 | scopes: Arc::new(scopes), | 453 | scopes: Arc::new(scopes), |
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs index b0bd735bd..a82205f0b 100644 --- a/crates/ra_hir/src/generics.rs +++ b/crates/ra_hir/src/generics.rs | |||
@@ -12,6 +12,7 @@ use crate::{db::PersistentHirDatabase, Name, AsName, Function, Struct, Enum, Tra | |||
12 | /// Data about a generic parameter (to a function, struct, impl, ...). | 12 | /// Data about a generic parameter (to a function, struct, impl, ...). |
13 | #[derive(Clone, PartialEq, Eq, Debug)] | 13 | #[derive(Clone, PartialEq, Eq, Debug)] |
14 | pub struct GenericParam { | 14 | pub struct GenericParam { |
15 | // TODO: give generic params proper IDs | ||
15 | pub(crate) idx: u32, | 16 | pub(crate) idx: u32, |
16 | pub(crate) name: Name, | 17 | pub(crate) name: Name, |
17 | } | 18 | } |
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs index 36d72b103..738c58fbe 100644 --- a/crates/ra_hir/src/impl_block.rs +++ b/crates/ra_hir/src/impl_block.rs | |||
@@ -7,11 +7,13 @@ use ra_syntax::{ | |||
7 | ast::{self, AstNode}}; | 7 | ast::{self, AstNode}}; |
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{ |
10 | Const, Type, | 10 | Const, Type, Function, HirFileId, |
11 | Function, HirFileId, | 11 | HirDatabase, PersistentHirDatabase, |
12 | PersistentHirDatabase, | 12 | ModuleDef, Trait, Resolution, |
13 | type_ref::TypeRef, | 13 | type_ref::TypeRef, |
14 | ids::LocationCtx, | 14 | ids::LocationCtx, |
15 | resolve::Resolver, | ||
16 | ty::Ty, | ||
15 | }; | 17 | }; |
16 | 18 | ||
17 | use crate::code_model_api::{Module, ModuleSource}; | 19 | use crate::code_model_api::{Module, ModuleSource}; |
@@ -69,7 +71,11 @@ impl ImplBlock { | |||
69 | &self.module_impl_blocks.impls[self.impl_id] | 71 | &self.module_impl_blocks.impls[self.impl_id] |
70 | } | 72 | } |
71 | 73 | ||
72 | pub fn target_trait(&self) -> Option<&TypeRef> { | 74 | pub fn module(&self) -> Module { |
75 | self.module_impl_blocks.module.clone() | ||
76 | } | ||
77 | |||
78 | pub fn target_trait_ref(&self) -> Option<&TypeRef> { | ||
73 | self.impl_data().target_trait() | 79 | self.impl_data().target_trait() |
74 | } | 80 | } |
75 | 81 | ||
@@ -77,9 +83,32 @@ impl ImplBlock { | |||
77 | self.impl_data().target_type() | 83 | self.impl_data().target_type() |
78 | } | 84 | } |
79 | 85 | ||
86 | pub fn target_ty(&self, db: &impl HirDatabase) -> Ty { | ||
87 | Ty::from_hir(db, &self.resolver(db), self.target_type()) | ||
88 | } | ||
89 | |||
90 | pub fn target_trait(&self, db: &impl HirDatabase) -> Option<Trait> { | ||
91 | if let Some(TypeRef::Path(path)) = self.target_trait_ref() { | ||
92 | let resolver = self.resolver(db); | ||
93 | if let Some(Resolution::Def(ModuleDef::Trait(tr))) = | ||
94 | resolver.resolve_path(db, path).take_types() | ||
95 | { | ||
96 | return Some(tr); | ||
97 | } | ||
98 | } | ||
99 | None | ||
100 | } | ||
101 | |||
80 | pub fn items(&self) -> &[ImplItem] { | 102 | pub fn items(&self) -> &[ImplItem] { |
81 | self.impl_data().items() | 103 | self.impl_data().items() |
82 | } | 104 | } |
105 | |||
106 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | ||
107 | let r = self.module().resolver(db); | ||
108 | // TODO: add generics | ||
109 | let r = r.push_impl_block_scope(self.clone()); | ||
110 | r | ||
111 | } | ||
83 | } | 112 | } |
84 | 113 | ||
85 | #[derive(Debug, Clone, PartialEq, Eq)] | 114 | #[derive(Debug, Clone, PartialEq, Eq)] |
@@ -162,25 +191,24 @@ impl_arena_id!(ImplId); | |||
162 | /// we don't need to do the second step again. | 191 | /// we don't need to do the second step again. |
163 | #[derive(Debug, PartialEq, Eq)] | 192 | #[derive(Debug, PartialEq, Eq)] |
164 | pub struct ModuleImplBlocks { | 193 | pub struct ModuleImplBlocks { |
194 | module: Module, | ||
165 | pub(crate) impls: Arena<ImplId, ImplData>, | 195 | pub(crate) impls: Arena<ImplId, ImplData>, |
166 | impls_by_def: FxHashMap<ImplItem, ImplId>, | 196 | impls_by_def: FxHashMap<ImplItem, ImplId>, |
167 | } | 197 | } |
168 | 198 | ||
169 | impl ModuleImplBlocks { | 199 | impl ModuleImplBlocks { |
170 | fn new() -> Self { | ||
171 | ModuleImplBlocks { | ||
172 | impls: Arena::default(), | ||
173 | impls_by_def: FxHashMap::default(), | ||
174 | } | ||
175 | } | ||
176 | |||
177 | fn collect( | 200 | fn collect( |
178 | &mut self, | ||
179 | db: &impl PersistentHirDatabase, | 201 | db: &impl PersistentHirDatabase, |
180 | module: Module, | 202 | module: Module, |
181 | source_map: &mut ImplSourceMap, | 203 | source_map: &mut ImplSourceMap, |
182 | ) { | 204 | ) -> Self { |
183 | let (file_id, module_source) = module.definition_source(db); | 205 | let mut m = ModuleImplBlocks { |
206 | module, | ||
207 | impls: Arena::default(), | ||
208 | impls_by_def: FxHashMap::default(), | ||
209 | }; | ||
210 | |||
211 | let (file_id, module_source) = m.module.definition_source(db); | ||
184 | let file_id: HirFileId = file_id.into(); | 212 | let file_id: HirFileId = file_id.into(); |
185 | let node = match &module_source { | 213 | let node = match &module_source { |
186 | ModuleSource::SourceFile(node) => node.syntax(), | 214 | ModuleSource::SourceFile(node) => node.syntax(), |
@@ -191,14 +219,16 @@ impl ModuleImplBlocks { | |||
191 | }; | 219 | }; |
192 | 220 | ||
193 | for impl_block_ast in node.children().filter_map(ast::ImplBlock::cast) { | 221 | for impl_block_ast in node.children().filter_map(ast::ImplBlock::cast) { |
194 | let impl_block = ImplData::from_ast(db, file_id, module, impl_block_ast); | 222 | let impl_block = ImplData::from_ast(db, file_id, m.module, impl_block_ast); |
195 | let id = self.impls.alloc(impl_block); | 223 | let id = m.impls.alloc(impl_block); |
196 | for &impl_item in &self.impls[id].items { | 224 | for &impl_item in &m.impls[id].items { |
197 | self.impls_by_def.insert(impl_item, id); | 225 | m.impls_by_def.insert(impl_item, id); |
198 | } | 226 | } |
199 | 227 | ||
200 | source_map.insert(id, impl_block_ast); | 228 | source_map.insert(id, impl_block_ast); |
201 | } | 229 | } |
230 | |||
231 | m | ||
202 | } | 232 | } |
203 | } | 233 | } |
204 | 234 | ||
@@ -208,8 +238,7 @@ pub(crate) fn impls_in_module_with_source_map_query( | |||
208 | ) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>) { | 238 | ) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>) { |
209 | let mut source_map = ImplSourceMap::default(); | 239 | let mut source_map = ImplSourceMap::default(); |
210 | 240 | ||
211 | let mut result = ModuleImplBlocks::new(); | 241 | let result = ModuleImplBlocks::collect(db, module, &mut source_map); |
212 | result.collect(db, module, &mut source_map); | ||
213 | 242 | ||
214 | (Arc::new(result), Arc::new(source_map)) | 243 | (Arc::new(result), Arc::new(source_map)) |
215 | } | 244 | } |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 905c53c7d..54da55598 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -36,6 +36,7 @@ mod impl_block; | |||
36 | mod expr; | 36 | mod expr; |
37 | mod generics; | 37 | mod generics; |
38 | mod docs; | 38 | mod docs; |
39 | mod resolve; | ||
39 | 40 | ||
40 | mod code_model_api; | 41 | mod code_model_api; |
41 | mod code_model_impl; | 42 | mod code_model_impl; |
@@ -54,12 +55,13 @@ pub use self::{ | |||
54 | name::Name, | 55 | name::Name, |
55 | ids::{HirFileId, MacroCallId, MacroCallLoc, HirInterner}, | 56 | ids::{HirFileId, MacroCallId, MacroCallLoc, HirInterner}, |
56 | macros::{MacroDef, MacroInput, MacroExpansion}, | 57 | macros::{MacroDef, MacroInput, MacroExpansion}, |
57 | nameres::{ItemMap, PerNs, Namespace, Resolution}, | 58 | nameres::{ItemMap, PerNs, Namespace}, |
58 | ty::Ty, | 59 | ty::Ty, |
59 | impl_block::{ImplBlock, ImplItem}, | 60 | impl_block::{ImplBlock, ImplItem}, |
60 | docs::{Docs, Documentation}, | 61 | docs::{Docs, Documentation}, |
61 | adt::AdtDef, | 62 | adt::AdtDef, |
62 | expr::{ExprScopes, ScopesWithSyntaxMapping}, | 63 | expr::{ExprScopes, ScopesWithSyntaxMapping}, |
64 | resolve::{Resolver, Resolution}, | ||
63 | }; | 65 | }; |
64 | 66 | ||
65 | pub use self::code_model_api::{ | 67 | pub use self::code_model_api::{ |
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index f8627acbe..7ec6512b6 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -24,13 +24,13 @@ use rustc_hash::{FxHashMap, FxHashSet}; | |||
24 | 24 | ||
25 | use crate::{ | 25 | use crate::{ |
26 | Module, ModuleDef, | 26 | Module, ModuleDef, |
27 | Path, PathKind, Crate, | 27 | Path, PathKind, PersistentHirDatabase, |
28 | Name, PersistentHirDatabase, | 28 | Crate, Name, |
29 | module_tree::{ModuleId, ModuleTree}, | 29 | module_tree::{ModuleId, ModuleTree}, |
30 | nameres::lower::{ImportId, LoweredModule, ImportData}, | 30 | nameres::lower::{ImportId, LoweredModule, ImportData}, |
31 | }; | 31 | }; |
32 | 32 | ||
33 | /// `ItemMap` is the result of name resolution. It contains, for each | 33 | /// `ItemMap` is the result of module name resolution. It contains, for each |
34 | /// module, the set of visible items. | 34 | /// module, the set of visible items. |
35 | #[derive(Default, Debug, PartialEq, Eq)] | 35 | #[derive(Default, Debug, PartialEq, Eq)] |
36 | pub struct ItemMap { | 36 | pub struct ItemMap { |
@@ -46,7 +46,7 @@ impl std::ops::Index<ModuleId> for ItemMap { | |||
46 | 46 | ||
47 | #[derive(Debug, Default, PartialEq, Eq, Clone)] | 47 | #[derive(Debug, Default, PartialEq, Eq, Clone)] |
48 | pub struct ModuleScope { | 48 | pub struct ModuleScope { |
49 | items: FxHashMap<Name, Resolution>, | 49 | pub(crate) items: FxHashMap<Name, Resolution>, |
50 | } | 50 | } |
51 | 51 | ||
52 | impl ModuleScope { | 52 | impl ModuleScope { |
@@ -80,6 +80,15 @@ pub struct PerNs<T> { | |||
80 | pub values: Option<T>, | 80 | pub values: Option<T>, |
81 | } | 81 | } |
82 | 82 | ||
83 | impl<T> Default for PerNs<T> { | ||
84 | fn default() -> Self { | ||
85 | PerNs { | ||
86 | types: None, | ||
87 | values: None, | ||
88 | } | ||
89 | } | ||
90 | } | ||
91 | |||
83 | impl<T> PerNs<T> { | 92 | impl<T> PerNs<T> { |
84 | pub fn none() -> PerNs<T> { | 93 | pub fn none() -> PerNs<T> { |
85 | PerNs { | 94 | PerNs { |
@@ -113,6 +122,10 @@ impl<T> PerNs<T> { | |||
113 | self.types.is_none() && self.values.is_none() | 122 | self.types.is_none() && self.values.is_none() |
114 | } | 123 | } |
115 | 124 | ||
125 | pub fn is_both(&self) -> bool { | ||
126 | self.types.is_some() && self.values.is_some() | ||
127 | } | ||
128 | |||
116 | pub fn take(self, namespace: Namespace) -> Option<T> { | 129 | pub fn take(self, namespace: Namespace) -> Option<T> { |
117 | match namespace { | 130 | match namespace { |
118 | Namespace::Types => self.types, | 131 | Namespace::Types => self.types, |
@@ -139,6 +152,13 @@ impl<T> PerNs<T> { | |||
139 | } | 152 | } |
140 | } | 153 | } |
141 | 154 | ||
155 | pub fn combine(self, other: PerNs<T>) -> PerNs<T> { | ||
156 | PerNs { | ||
157 | types: self.types.or(other.types), | ||
158 | values: self.values.or(other.values), | ||
159 | } | ||
160 | } | ||
161 | |||
142 | pub fn and_then<U>(self, f: impl Fn(T) -> Option<U>) -> PerNs<U> { | 162 | pub fn and_then<U>(self, f: impl Fn(T) -> Option<U>) -> PerNs<U> { |
143 | PerNs { | 163 | PerNs { |
144 | types: self.types.and_then(&f), | 164 | types: self.types.and_then(&f), |
@@ -402,10 +422,11 @@ impl ItemMap { | |||
402 | if module.krate != original_module.krate { | 422 | if module.krate != original_module.krate { |
403 | let path = Path { | 423 | let path = Path { |
404 | segments: path.segments[i..].iter().cloned().collect(), | 424 | segments: path.segments[i..].iter().cloned().collect(), |
405 | kind: PathKind::Crate, | 425 | kind: PathKind::Self_, |
406 | }; | 426 | }; |
407 | log::debug!("resolving {:?} in other crate", path); | 427 | log::debug!("resolving {:?} in other crate", path); |
408 | let def = module.resolve_path(db, &path); | 428 | let item_map = db.item_map(module.krate); |
429 | let def = item_map.resolve_path(db, *module, &path); | ||
409 | return (def, ReachedFixedPoint::Yes); | 430 | return (def, ReachedFixedPoint::Yes); |
410 | } | 431 | } |
411 | 432 | ||
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs index 1ce7bd146..0e0683db7 100644 --- a/crates/ra_hir/src/nameres/tests.rs +++ b/crates/ra_hir/src/nameres/tests.rs | |||
@@ -5,11 +5,12 @@ use relative_path::RelativePath; | |||
5 | use test_utils::{assert_eq_text, covers}; | 5 | use test_utils::{assert_eq_text, covers}; |
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
8 | ItemMap, Resolution, | 8 | ItemMap, |
9 | PersistentHirDatabase, | 9 | PersistentHirDatabase, |
10 | mock::MockDatabase, | 10 | mock::MockDatabase, |
11 | module_tree::ModuleId, | 11 | module_tree::ModuleId, |
12 | }; | 12 | }; |
13 | use super::Resolution; | ||
13 | 14 | ||
14 | fn item_map(fixture: &str) -> (Arc<ItemMap>, ModuleId) { | 15 | fn item_map(fixture: &str) -> (Arc<ItemMap>, ModuleId) { |
15 | let (db, pos) = MockDatabase::with_position(fixture); | 16 | let (db, pos) = MockDatabase::with_position(fixture); |
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs new file mode 100644 index 000000000..6c87d0df7 --- /dev/null +++ b/crates/ra_hir/src/resolve.rs | |||
@@ -0,0 +1,226 @@ | |||
1 | //! Name resolution. | ||
2 | use std::sync::Arc; | ||
3 | |||
4 | use rustc_hash::FxHashMap; | ||
5 | |||
6 | use crate::{ | ||
7 | ModuleDef, Module, | ||
8 | db::HirDatabase, | ||
9 | name::{Name, KnownName}, | ||
10 | nameres::{PerNs, ItemMap}, | ||
11 | generics::GenericParams, | ||
12 | expr::{scope::{ExprScopes, ScopeId}, PatId, Body}, | ||
13 | impl_block::ImplBlock, | ||
14 | path::Path, | ||
15 | }; | ||
16 | |||
17 | #[derive(Debug, Clone, Default)] | ||
18 | pub struct Resolver { | ||
19 | scopes: Vec<Scope>, | ||
20 | } | ||
21 | |||
22 | // TODO how to store these best | ||
23 | #[derive(Debug, Clone)] | ||
24 | pub(crate) struct ModuleItemMap { | ||
25 | item_map: Arc<ItemMap>, | ||
26 | module: Module, | ||
27 | } | ||
28 | |||
29 | #[derive(Debug, Clone)] | ||
30 | pub(crate) struct ExprScope { | ||
31 | expr_scopes: Arc<ExprScopes>, | ||
32 | scope_id: ScopeId, | ||
33 | } | ||
34 | |||
35 | #[derive(Debug, Clone)] | ||
36 | pub(crate) enum Scope { | ||
37 | /// All the items and imported names of a module | ||
38 | ModuleScope(ModuleItemMap), | ||
39 | /// Brings the generic parameters of an item into scope | ||
40 | GenericParams(Arc<GenericParams>), | ||
41 | /// Brings `Self` into scope | ||
42 | ImplBlockScope(ImplBlock), | ||
43 | /// Local bindings | ||
44 | ExprScope(ExprScope), | ||
45 | } | ||
46 | |||
47 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
48 | pub enum Resolution { | ||
49 | /// An item | ||
50 | Def(ModuleDef), | ||
51 | /// A local binding (only value namespace) | ||
52 | LocalBinding(PatId), | ||
53 | /// A generic parameter | ||
54 | GenericParam(u32), | ||
55 | SelfType(ImplBlock), | ||
56 | } | ||
57 | |||
58 | impl Resolver { | ||
59 | pub fn resolve_name(&self, name: &Name) -> PerNs<Resolution> { | ||
60 | let mut resolution = PerNs::none(); | ||
61 | for scope in self.scopes.iter().rev() { | ||
62 | resolution = resolution.combine(scope.resolve_name(name)); | ||
63 | if resolution.is_both() { | ||
64 | return resolution; | ||
65 | } | ||
66 | } | ||
67 | resolution | ||
68 | } | ||
69 | |||
70 | pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs<Resolution> { | ||
71 | if let Some(name) = path.as_ident() { | ||
72 | self.resolve_name(name) | ||
73 | } else if path.is_self() { | ||
74 | self.resolve_name(&Name::self_param()) | ||
75 | } else { | ||
76 | let (item_map, module) = match self.module() { | ||
77 | Some(m) => m, | ||
78 | _ => return PerNs::none(), | ||
79 | }; | ||
80 | let module_res = item_map.resolve_path(db, module, path); | ||
81 | module_res.map(|def| Resolution::Def(def)) | ||
82 | } | ||
83 | } | ||
84 | |||
85 | pub fn all_names(&self) -> FxHashMap<Name, PerNs<Resolution>> { | ||
86 | let mut names = FxHashMap::default(); | ||
87 | for scope in self.scopes.iter().rev() { | ||
88 | scope.collect_names(&mut |name, res| { | ||
89 | let current: &mut PerNs<Resolution> = names.entry(name).or_default(); | ||
90 | if current.types.is_none() { | ||
91 | current.types = res.types; | ||
92 | } | ||
93 | if current.values.is_none() { | ||
94 | current.values = res.values; | ||
95 | } | ||
96 | }); | ||
97 | } | ||
98 | names | ||
99 | } | ||
100 | |||
101 | fn module(&self) -> Option<(&ItemMap, Module)> { | ||
102 | self.scopes.iter().rev().find_map(|scope| match scope { | ||
103 | Scope::ModuleScope(m) => Some((&*m.item_map, m.module.clone())), | ||
104 | |||
105 | _ => None, | ||
106 | }) | ||
107 | } | ||
108 | |||
109 | /// The body from which any `LocalBinding` resolutions in this resolver come. | ||
110 | pub fn body(&self) -> Option<Arc<Body>> { | ||
111 | self.scopes.iter().rev().find_map(|scope| match scope { | ||
112 | Scope::ExprScope(expr_scope) => Some(expr_scope.expr_scopes.body()), | ||
113 | _ => None, | ||
114 | }) | ||
115 | } | ||
116 | } | ||
117 | |||
118 | impl Resolver { | ||
119 | pub(crate) fn push_scope(mut self, scope: Scope) -> Resolver { | ||
120 | self.scopes.push(scope); | ||
121 | self | ||
122 | } | ||
123 | |||
124 | pub(crate) fn push_generic_params_scope(self, params: Arc<GenericParams>) -> Resolver { | ||
125 | self.push_scope(Scope::GenericParams(params)) | ||
126 | } | ||
127 | |||
128 | pub(crate) fn push_impl_block_scope(self, impl_block: ImplBlock) -> Resolver { | ||
129 | self.push_scope(Scope::ImplBlockScope(impl_block)) | ||
130 | } | ||
131 | |||
132 | pub(crate) fn push_module_scope(self, item_map: Arc<ItemMap>, module: Module) -> Resolver { | ||
133 | self.push_scope(Scope::ModuleScope(ModuleItemMap { item_map, module })) | ||
134 | } | ||
135 | |||
136 | pub(crate) fn push_expr_scope( | ||
137 | self, | ||
138 | expr_scopes: Arc<ExprScopes>, | ||
139 | scope_id: ScopeId, | ||
140 | ) -> Resolver { | ||
141 | self.push_scope(Scope::ExprScope(ExprScope { | ||
142 | expr_scopes, | ||
143 | scope_id, | ||
144 | })) | ||
145 | } | ||
146 | } | ||
147 | |||
148 | impl Scope { | ||
149 | fn resolve_name(&self, name: &Name) -> PerNs<Resolution> { | ||
150 | match self { | ||
151 | Scope::ModuleScope(m) => { | ||
152 | if let Some(KnownName::SelfParam) = name.as_known_name() { | ||
153 | PerNs::types(Resolution::Def(m.module.into())) | ||
154 | } else { | ||
155 | match m.item_map[m.module.module_id].get(name) { | ||
156 | Some(res) => res.def.map(Resolution::Def), | ||
157 | None => PerNs::none(), | ||
158 | } | ||
159 | } | ||
160 | } | ||
161 | Scope::GenericParams(gp) => match gp.find_by_name(name) { | ||
162 | Some(gp) => PerNs::types(Resolution::GenericParam(gp.idx)), | ||
163 | None => PerNs::none(), | ||
164 | }, | ||
165 | Scope::ImplBlockScope(i) => { | ||
166 | if name.as_known_name() == Some(KnownName::SelfType) { | ||
167 | PerNs::types(Resolution::SelfType(i.clone())) | ||
168 | } else { | ||
169 | PerNs::none() | ||
170 | } | ||
171 | } | ||
172 | Scope::ExprScope(e) => { | ||
173 | let entry = e | ||
174 | .expr_scopes | ||
175 | .entries(e.scope_id) | ||
176 | .iter() | ||
177 | .find(|entry| entry.name() == name); | ||
178 | match entry { | ||
179 | Some(e) => PerNs::values(Resolution::LocalBinding(e.pat())), | ||
180 | None => PerNs::none(), | ||
181 | } | ||
182 | } | ||
183 | } | ||
184 | } | ||
185 | |||
186 | fn collect_names(&self, f: &mut FnMut(Name, PerNs<Resolution>)) { | ||
187 | match self { | ||
188 | Scope::ModuleScope(m) => { | ||
189 | // TODO: should we provide `self` here? | ||
190 | // f( | ||
191 | // Name::self_param(), | ||
192 | // PerNs::types(Resolution::Def { | ||
193 | // def: m.module.into(), | ||
194 | // }), | ||
195 | // ); | ||
196 | m.item_map[m.module.module_id] | ||
197 | .entries() | ||
198 | .for_each(|(name, res)| { | ||
199 | f(name.clone(), res.def.map(Resolution::Def)); | ||
200 | }) | ||
201 | } | ||
202 | Scope::GenericParams(gp) => { | ||
203 | for param in &gp.params { | ||
204 | f( | ||
205 | param.name.clone(), | ||
206 | PerNs::types(Resolution::GenericParam(param.idx)), | ||
207 | ) | ||
208 | } | ||
209 | } | ||
210 | Scope::ImplBlockScope(i) => { | ||
211 | f( | ||
212 | Name::self_type(), | ||
213 | PerNs::types(Resolution::SelfType(i.clone())), | ||
214 | ); | ||
215 | } | ||
216 | Scope::ExprScope(e) => { | ||
217 | e.expr_scopes.entries(e.scope_id).iter().for_each(|e| { | ||
218 | f( | ||
219 | e.name().clone(), | ||
220 | PerNs::values(Resolution::LocalBinding(e.pat())), | ||
221 | ); | ||
222 | }); | ||
223 | } | ||
224 | } | ||
225 | } | ||
226 | } | ||
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index a1b94ed9c..59f782277 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -9,13 +9,14 @@ use ra_db::{FileId, FilePosition}; | |||
9 | use ra_syntax::{ | 9 | use ra_syntax::{ |
10 | SmolStr, TextRange, SyntaxNode, | 10 | SmolStr, TextRange, SyntaxNode, |
11 | ast::{self, AstNode, NameOwner}, | 11 | ast::{self, AstNode, NameOwner}, |
12 | algo::find_node_at_offset, | 12 | algo::{find_node_at_offset, find_leaf_at_offset}, |
13 | }; | 13 | }; |
14 | 14 | ||
15 | use crate::{ | 15 | use crate::{ |
16 | HirDatabase, Function, ModuleDef, Struct, Enum, | 16 | HirDatabase, Function, ModuleDef, Struct, Enum, |
17 | AsName, Module, HirFileId, Crate, Trait, | 17 | AsName, Module, HirFileId, Crate, Trait, Resolver, |
18 | ids::{LocationCtx, SourceFileItemId}, | 18 | ids::{LocationCtx, SourceFileItemId}, |
19 | expr | ||
19 | }; | 20 | }; |
20 | 21 | ||
21 | /// Locates the module by `FileId`. Picks topmost module in the file. | 22 | /// Locates the module by `FileId`. Picks topmost module in the file. |
@@ -201,3 +202,67 @@ pub fn macro_symbols(db: &impl HirDatabase, file_id: FileId) -> Vec<(SmolStr, Te | |||
201 | 202 | ||
202 | res | 203 | res |
203 | } | 204 | } |
205 | |||
206 | pub fn resolver_for_position(db: &impl HirDatabase, position: FilePosition) -> Resolver { | ||
207 | let file_id = position.file_id; | ||
208 | let file = db.parse(file_id); | ||
209 | find_leaf_at_offset(file.syntax(), position.offset) | ||
210 | .find_map(|node| { | ||
211 | node.ancestors().find_map(|node| { | ||
212 | if ast::Expr::cast(node).is_some() || ast::Block::cast(node).is_some() { | ||
213 | if let Some(func) = function_from_child_node(db, file_id, node) { | ||
214 | let scopes = func.scopes(db); | ||
215 | let scope = scopes.scope_for_offset(position.offset); | ||
216 | Some(expr::resolver_for_scope(func.body(db), db, scope)) | ||
217 | } else { | ||
218 | // TODO const/static/array length | ||
219 | None | ||
220 | } | ||
221 | } else if let Some(module) = ast::Module::cast(node) { | ||
222 | Some(module_from_declaration(db, file_id, module)?.resolver(db)) | ||
223 | } else if let Some(_) = ast::SourceFile::cast(node) { | ||
224 | Some(module_from_source(db, file_id.into(), None)?.resolver(db)) | ||
225 | } else if let Some(s) = ast::StructDef::cast(node) { | ||
226 | let module = module_from_child_node(db, file_id, s.syntax())?; | ||
227 | Some(struct_from_module(db, module, s).resolver(db)) | ||
228 | } else if let Some(e) = ast::EnumDef::cast(node) { | ||
229 | let module = module_from_child_node(db, file_id, e.syntax())?; | ||
230 | Some(enum_from_module(db, module, e).resolver(db)) | ||
231 | } else { | ||
232 | // TODO add missing cases | ||
233 | None | ||
234 | } | ||
235 | }) | ||
236 | }) | ||
237 | .unwrap_or_default() | ||
238 | } | ||
239 | |||
240 | pub fn resolver_for_node(db: &impl HirDatabase, file_id: FileId, node: &SyntaxNode) -> Resolver { | ||
241 | node.ancestors() | ||
242 | .find_map(|node| { | ||
243 | if ast::Expr::cast(node).is_some() || ast::Block::cast(node).is_some() { | ||
244 | if let Some(func) = function_from_child_node(db, file_id, node) { | ||
245 | let scopes = func.scopes(db); | ||
246 | let scope = scopes.scope_for(&node); | ||
247 | Some(expr::resolver_for_scope(func.body(db), db, scope)) | ||
248 | } else { | ||
249 | // TODO const/static/array length | ||
250 | None | ||
251 | } | ||
252 | } else if let Some(module) = ast::Module::cast(node) { | ||
253 | Some(module_from_declaration(db, file_id, module)?.resolver(db)) | ||
254 | } else if let Some(_) = ast::SourceFile::cast(node) { | ||
255 | Some(module_from_source(db, file_id.into(), None)?.resolver(db)) | ||
256 | } else if let Some(s) = ast::StructDef::cast(node) { | ||
257 | let module = module_from_child_node(db, file_id, s.syntax())?; | ||
258 | Some(struct_from_module(db, module, s).resolver(db)) | ||
259 | } else if let Some(e) = ast::EnumDef::cast(node) { | ||
260 | let module = module_from_child_node(db, file_id, e.syntax())?; | ||
261 | Some(enum_from_module(db, module, e).resolver(db)) | ||
262 | } else { | ||
263 | // TODO add missing cases | ||
264 | None | ||
265 | } | ||
266 | }) | ||
267 | .unwrap_or_default() | ||
268 | } | ||
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index d3e31981a..cc5afad75 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -33,15 +33,16 @@ use rustc_hash::FxHashMap; | |||
33 | use test_utils::tested_by; | 33 | use test_utils::tested_by; |
34 | 34 | ||
35 | use crate::{ | 35 | use crate::{ |
36 | Module, Function, Struct, StructField, Enum, EnumVariant, Path, Name, ImplBlock, | 36 | Function, Struct, StructField, Enum, EnumVariant, Path, Name, |
37 | FnSignature, ExprScopes, ModuleDef, AdtDef, | 37 | FnSignature, ModuleDef, AdtDef, |
38 | HirDatabase, | 38 | HirDatabase, |
39 | type_ref::{TypeRef, Mutability}, | 39 | type_ref::{TypeRef, Mutability}, |
40 | name::KnownName, | 40 | name::KnownName, |
41 | expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat}, | 41 | expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat, self}, |
42 | generics::GenericParams, | 42 | generics::GenericParams, |
43 | path::GenericArg, | 43 | path::GenericArg, |
44 | adt::VariantDef, | 44 | adt::VariantDef, |
45 | resolve::{Resolver, Resolution}, | ||
45 | }; | 46 | }; |
46 | 47 | ||
47 | /// The ID of a type variable. | 48 | /// The ID of a type variable. |
@@ -300,47 +301,38 @@ pub struct FnSig { | |||
300 | } | 301 | } |
301 | 302 | ||
302 | impl Ty { | 303 | impl Ty { |
303 | pub(crate) fn from_hir( | 304 | pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self { |
304 | db: &impl HirDatabase, | ||
305 | // TODO: the next three parameters basically describe the scope for name | ||
306 | // resolution; this should be refactored into something like a general | ||
307 | // resolver architecture | ||
308 | module: &Module, | ||
309 | impl_block: Option<&ImplBlock>, | ||
310 | generics: &GenericParams, | ||
311 | type_ref: &TypeRef, | ||
312 | ) -> Self { | ||
313 | match type_ref { | 305 | match type_ref { |
314 | TypeRef::Never => Ty::Never, | 306 | TypeRef::Never => Ty::Never, |
315 | TypeRef::Tuple(inner) => { | 307 | TypeRef::Tuple(inner) => { |
316 | let inner_tys = inner | 308 | let inner_tys = inner |
317 | .iter() | 309 | .iter() |
318 | .map(|tr| Ty::from_hir(db, module, impl_block, generics, tr)) | 310 | .map(|tr| Ty::from_hir(db, resolver, tr)) |
319 | .collect::<Vec<_>>(); | 311 | .collect::<Vec<_>>(); |
320 | Ty::Tuple(inner_tys.into()) | 312 | Ty::Tuple(inner_tys.into()) |
321 | } | 313 | } |
322 | TypeRef::Path(path) => Ty::from_hir_path(db, module, impl_block, generics, path), | 314 | TypeRef::Path(path) => Ty::from_hir_path(db, resolver, path), |
323 | TypeRef::RawPtr(inner, mutability) => { | 315 | TypeRef::RawPtr(inner, mutability) => { |
324 | let inner_ty = Ty::from_hir(db, module, impl_block, generics, inner); | 316 | let inner_ty = Ty::from_hir(db, resolver, inner); |
325 | Ty::RawPtr(Arc::new(inner_ty), *mutability) | 317 | Ty::RawPtr(Arc::new(inner_ty), *mutability) |
326 | } | 318 | } |
327 | TypeRef::Array(inner) => { | 319 | TypeRef::Array(inner) => { |
328 | let inner_ty = Ty::from_hir(db, module, impl_block, generics, inner); | 320 | let inner_ty = Ty::from_hir(db, resolver, inner); |
329 | Ty::Array(Arc::new(inner_ty)) | 321 | Ty::Array(Arc::new(inner_ty)) |
330 | } | 322 | } |
331 | TypeRef::Slice(inner) => { | 323 | TypeRef::Slice(inner) => { |
332 | let inner_ty = Ty::from_hir(db, module, impl_block, generics, inner); | 324 | let inner_ty = Ty::from_hir(db, resolver, inner); |
333 | Ty::Slice(Arc::new(inner_ty)) | 325 | Ty::Slice(Arc::new(inner_ty)) |
334 | } | 326 | } |
335 | TypeRef::Reference(inner, mutability) => { | 327 | TypeRef::Reference(inner, mutability) => { |
336 | let inner_ty = Ty::from_hir(db, module, impl_block, generics, inner); | 328 | let inner_ty = Ty::from_hir(db, resolver, inner); |
337 | Ty::Ref(Arc::new(inner_ty), *mutability) | 329 | Ty::Ref(Arc::new(inner_ty), *mutability) |
338 | } | 330 | } |
339 | TypeRef::Placeholder => Ty::Unknown, | 331 | TypeRef::Placeholder => Ty::Unknown, |
340 | TypeRef::Fn(params) => { | 332 | TypeRef::Fn(params) => { |
341 | let mut inner_tys = params | 333 | let mut inner_tys = params |
342 | .iter() | 334 | .iter() |
343 | .map(|tr| Ty::from_hir(db, module, impl_block, generics, tr)) | 335 | .map(|tr| Ty::from_hir(db, resolver, tr)) |
344 | .collect::<Vec<_>>(); | 336 | .collect::<Vec<_>>(); |
345 | let return_ty = inner_tys | 337 | let return_ty = inner_tys |
346 | .pop() | 338 | .pop() |
@@ -355,40 +347,13 @@ impl Ty { | |||
355 | } | 347 | } |
356 | } | 348 | } |
357 | 349 | ||
358 | pub(crate) fn from_hir_opt( | 350 | pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Self { |
359 | db: &impl HirDatabase, | ||
360 | module: &Module, | ||
361 | impl_block: Option<&ImplBlock>, | ||
362 | generics: &GenericParams, | ||
363 | type_ref: Option<&TypeRef>, | ||
364 | ) -> Self { | ||
365 | type_ref.map_or(Ty::Unknown, |t| { | ||
366 | Ty::from_hir(db, module, impl_block, generics, t) | ||
367 | }) | ||
368 | } | ||
369 | |||
370 | pub(crate) fn from_hir_path( | ||
371 | db: &impl HirDatabase, | ||
372 | module: &Module, | ||
373 | impl_block: Option<&ImplBlock>, | ||
374 | generics: &GenericParams, | ||
375 | path: &Path, | ||
376 | ) -> Self { | ||
377 | if let Some(name) = path.as_ident() { | 351 | if let Some(name) = path.as_ident() { |
352 | // TODO handle primitive type names in resolver as well? | ||
378 | if let Some(int_ty) = primitive::UncertainIntTy::from_name(name) { | 353 | if let Some(int_ty) = primitive::UncertainIntTy::from_name(name) { |
379 | return Ty::Int(int_ty); | 354 | return Ty::Int(int_ty); |
380 | } else if let Some(float_ty) = primitive::UncertainFloatTy::from_name(name) { | 355 | } else if let Some(float_ty) = primitive::UncertainFloatTy::from_name(name) { |
381 | return Ty::Float(float_ty); | 356 | return Ty::Float(float_ty); |
382 | } else if name.as_known_name() == Some(KnownName::SelfType) { | ||
383 | // TODO pass the impl block's generics? | ||
384 | let generics = &GenericParams::default(); | ||
385 | return Ty::from_hir_opt( | ||
386 | db, | ||
387 | module, | ||
388 | None, | ||
389 | generics, | ||
390 | impl_block.map(|i| i.target_type()), | ||
391 | ); | ||
392 | } else if let Some(known) = name.as_known_name() { | 357 | } else if let Some(known) = name.as_known_name() { |
393 | match known { | 358 | match known { |
394 | KnownName::Bool => return Ty::Bool, | 359 | KnownName::Bool => return Ty::Bool, |
@@ -396,25 +361,40 @@ impl Ty { | |||
396 | KnownName::Str => return Ty::Str, | 361 | KnownName::Str => return Ty::Str, |
397 | _ => {} | 362 | _ => {} |
398 | } | 363 | } |
399 | } else if let Some(generic_param) = generics.find_by_name(&name) { | 364 | } |
365 | } | ||
366 | |||
367 | // Resolve the path (in type namespace) | ||
368 | let resolution = resolver.resolve_path(db, path).take_types(); | ||
369 | |||
370 | let def = match resolution { | ||
371 | Some(Resolution::Def(def)) => def, | ||
372 | Some(Resolution::LocalBinding(..)) => { | ||
373 | // this should never happen | ||
374 | panic!("path resolved to local binding in type ns"); | ||
375 | } | ||
376 | Some(Resolution::GenericParam(idx)) => { | ||
400 | return Ty::Param { | 377 | return Ty::Param { |
401 | idx: generic_param.idx, | 378 | idx, |
402 | name: generic_param.name.clone(), | 379 | // TODO: maybe return name in resolution? |
380 | name: path | ||
381 | .as_ident() | ||
382 | .expect("generic param should be single-segment path") | ||
383 | .clone(), | ||
403 | }; | 384 | }; |
404 | } | 385 | } |
405 | } | 386 | Some(Resolution::SelfType(impl_block)) => { |
387 | return impl_block.target_ty(db); | ||
388 | } | ||
389 | None => return Ty::Unknown, | ||
390 | }; | ||
406 | 391 | ||
407 | // Resolve in module (in type namespace) | 392 | let typable: TypableDef = match def.into() { |
408 | let typable: TypableDef = match module | ||
409 | .resolve_path(db, path) | ||
410 | .take_types() | ||
411 | .and_then(|it| it.into()) | ||
412 | { | ||
413 | None => return Ty::Unknown, | 393 | None => return Ty::Unknown, |
414 | Some(it) => it, | 394 | Some(it) => it, |
415 | }; | 395 | }; |
416 | let ty = db.type_for_def(typable); | 396 | let ty = db.type_for_def(typable); |
417 | let substs = Ty::substs_from_path(db, module, impl_block, generics, path, typable); | 397 | let substs = Ty::substs_from_path(db, resolver, path, typable); |
418 | ty.apply_substs(substs) | 398 | ty.apply_substs(substs) |
419 | } | 399 | } |
420 | 400 | ||
@@ -422,10 +402,7 @@ impl Ty { | |||
422 | /// `create_substs_for_ast_path` and `def_to_ty` in rustc. | 402 | /// `create_substs_for_ast_path` and `def_to_ty` in rustc. |
423 | fn substs_from_path( | 403 | fn substs_from_path( |
424 | db: &impl HirDatabase, | 404 | db: &impl HirDatabase, |
425 | // the scope of the segment... | 405 | resolver: &Resolver, |
426 | module: &Module, | ||
427 | impl_block: Option<&ImplBlock>, | ||
428 | outer_generics: &GenericParams, | ||
429 | path: &Path, | 406 | path: &Path, |
430 | resolved: TypableDef, | 407 | resolved: TypableDef, |
431 | ) -> Substs { | 408 | ) -> Substs { |
@@ -462,7 +439,7 @@ impl Ty { | |||
462 | for arg in generic_args.args.iter().take(param_count) { | 439 | for arg in generic_args.args.iter().take(param_count) { |
463 | match arg { | 440 | match arg { |
464 | GenericArg::Type(type_ref) => { | 441 | GenericArg::Type(type_ref) => { |
465 | let ty = Ty::from_hir(db, module, impl_block, outer_generics, type_ref); | 442 | let ty = Ty::from_hir(db, resolver, type_ref); |
466 | substs.push(ty); | 443 | substs.push(ty); |
467 | } | 444 | } |
468 | } | 445 | } |
@@ -666,24 +643,17 @@ impl fmt::Display for Ty { | |||
666 | /// function body. | 643 | /// function body. |
667 | fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty { | 644 | fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty { |
668 | let signature = def.signature(db); | 645 | let signature = def.signature(db); |
669 | let module = def.module(db); | 646 | let resolver = def.resolver(db); |
670 | let impl_block = def.impl_block(db); | ||
671 | let generics = def.generic_params(db); | 647 | let generics = def.generic_params(db); |
648 | let name = def.name(db); | ||
672 | let input = signature | 649 | let input = signature |
673 | .params() | 650 | .params() |
674 | .iter() | 651 | .iter() |
675 | .map(|tr| Ty::from_hir(db, &module, impl_block.as_ref(), &generics, tr)) | 652 | .map(|tr| Ty::from_hir(db, &resolver, tr)) |
676 | .collect::<Vec<_>>(); | 653 | .collect::<Vec<_>>(); |
677 | let output = Ty::from_hir( | 654 | let output = Ty::from_hir(db, &resolver, signature.ret_type()); |
678 | db, | ||
679 | &module, | ||
680 | impl_block.as_ref(), | ||
681 | &generics, | ||
682 | signature.ret_type(), | ||
683 | ); | ||
684 | let sig = Arc::new(FnSig { input, output }); | 655 | let sig = Arc::new(FnSig { input, output }); |
685 | let substs = make_substs(&generics); | 656 | let substs = make_substs(&generics); |
686 | let name = def.name(db); | ||
687 | Ty::FnDef { | 657 | Ty::FnDef { |
688 | def, | 658 | def, |
689 | sig, | 659 | sig, |
@@ -764,13 +734,13 @@ pub(super) fn type_for_def(db: &impl HirDatabase, def: TypableDef) -> Ty { | |||
764 | 734 | ||
765 | pub(super) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty { | 735 | pub(super) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty { |
766 | let parent_def = field.parent_def(db); | 736 | let parent_def = field.parent_def(db); |
767 | let (generics, module) = match parent_def { | 737 | let resolver = match parent_def { |
768 | VariantDef::Struct(it) => (it.generic_params(db), it.module(db)), | 738 | VariantDef::Struct(it) => it.resolver(db), |
769 | VariantDef::EnumVariant(it) => (it.parent_enum(db).generic_params(db), it.module(db)), | 739 | VariantDef::EnumVariant(it) => it.parent_enum(db).resolver(db), |
770 | }; | 740 | }; |
771 | let var_data = parent_def.variant_data(db); | 741 | let var_data = parent_def.variant_data(db); |
772 | let type_ref = &var_data.fields().unwrap()[field.id].type_ref; | 742 | let type_ref = &var_data.fields().unwrap()[field.id].type_ref; |
773 | Ty::from_hir(db, &module, None, &generics, type_ref) | 743 | Ty::from_hir(db, &resolver, type_ref) |
774 | } | 744 | } |
775 | 745 | ||
776 | /// The result of type inference: A mapping from expressions and patterns to types. | 746 | /// The result of type inference: A mapping from expressions and patterns to types. |
@@ -814,9 +784,7 @@ impl Index<PatId> for InferenceResult { | |||
814 | struct InferenceContext<'a, D: HirDatabase> { | 784 | struct InferenceContext<'a, D: HirDatabase> { |
815 | db: &'a D, | 785 | db: &'a D, |
816 | body: Arc<Body>, | 786 | body: Arc<Body>, |
817 | scopes: Arc<ExprScopes>, | 787 | resolver: Resolver, |
818 | module: Module, | ||
819 | impl_block: Option<ImplBlock>, | ||
820 | var_unification_table: InPlaceUnificationTable<TypeVarId>, | 788 | var_unification_table: InPlaceUnificationTable<TypeVarId>, |
821 | method_resolutions: FxHashMap<ExprId, Function>, | 789 | method_resolutions: FxHashMap<ExprId, Function>, |
822 | field_resolutions: FxHashMap<ExprId, StructField>, | 790 | field_resolutions: FxHashMap<ExprId, StructField>, |
@@ -905,13 +873,7 @@ fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty { | |||
905 | } | 873 | } |
906 | 874 | ||
907 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 875 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
908 | fn new( | 876 | fn new(db: &'a D, body: Arc<Body>, resolver: Resolver) -> Self { |
909 | db: &'a D, | ||
910 | body: Arc<Body>, | ||
911 | scopes: Arc<ExprScopes>, | ||
912 | module: Module, | ||
913 | impl_block: Option<ImplBlock>, | ||
914 | ) -> Self { | ||
915 | InferenceContext { | 877 | InferenceContext { |
916 | method_resolutions: FxHashMap::default(), | 878 | method_resolutions: FxHashMap::default(), |
917 | field_resolutions: FxHashMap::default(), | 879 | field_resolutions: FxHashMap::default(), |
@@ -921,9 +883,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
921 | return_ty: Ty::Unknown, // set in collect_fn_signature | 883 | return_ty: Ty::Unknown, // set in collect_fn_signature |
922 | db, | 884 | db, |
923 | body, | 885 | body, |
924 | scopes, | 886 | resolver, |
925 | module, | ||
926 | impl_block, | ||
927 | } | 887 | } |
928 | } | 888 | } |
929 | 889 | ||
@@ -940,8 +900,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
940 | *ty = resolved; | 900 | *ty = resolved; |
941 | } | 901 | } |
942 | InferenceResult { | 902 | InferenceResult { |
943 | method_resolutions: mem::replace(&mut self.method_resolutions, Default::default()), | 903 | method_resolutions: self.method_resolutions, |
944 | field_resolutions: mem::replace(&mut self.field_resolutions, Default::default()), | 904 | field_resolutions: self.field_resolutions, |
945 | type_of_expr: expr_types, | 905 | type_of_expr: expr_types, |
946 | type_of_pat: pat_types, | 906 | type_of_pat: pat_types, |
947 | } | 907 | } |
@@ -964,13 +924,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
964 | } | 924 | } |
965 | 925 | ||
966 | fn make_ty(&mut self, type_ref: &TypeRef) -> Ty { | 926 | fn make_ty(&mut self, type_ref: &TypeRef) -> Ty { |
967 | // TODO provide generics of function | ||
968 | let generics = GenericParams::default(); | ||
969 | let ty = Ty::from_hir( | 927 | let ty = Ty::from_hir( |
970 | self.db, | 928 | self.db, |
971 | &self.module, | 929 | // TODO use right resolver for block |
972 | self.impl_block.as_ref(), | 930 | &self.resolver, |
973 | &generics, | ||
974 | type_ref, | 931 | type_ref, |
975 | ); | 932 | ); |
976 | let ty = self.insert_type_vars(ty); | 933 | let ty = self.insert_type_vars(ty); |
@@ -1147,38 +1104,31 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1147 | }) | 1104 | }) |
1148 | } | 1105 | } |
1149 | 1106 | ||
1150 | fn infer_path_expr(&mut self, expr: ExprId, path: &Path) -> Option<Ty> { | 1107 | fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path) -> Option<Ty> { |
1151 | if path.is_ident() || path.is_self() { | 1108 | let resolved = resolver.resolve_path(self.db, &path).take_values()?; |
1152 | // resolve locally | 1109 | match resolved { |
1153 | let name = path.as_ident().cloned().unwrap_or_else(Name::self_param); | 1110 | Resolution::Def(def) => { |
1154 | if let Some(scope_entry) = self.scopes.resolve_local_name(expr, name) { | 1111 | let typable: Option<TypableDef> = def.into(); |
1155 | let ty = self.type_of_pat.get(scope_entry.pat())?; | 1112 | let typable = typable?; |
1113 | let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); | ||
1114 | let ty = self.db.type_for_def(typable).apply_substs(substs); | ||
1115 | let ty = self.insert_type_vars(ty); | ||
1116 | Some(ty) | ||
1117 | } | ||
1118 | Resolution::LocalBinding(pat) => { | ||
1119 | let ty = self.type_of_pat.get(pat)?; | ||
1156 | let ty = self.resolve_ty_as_possible(&mut vec![], ty.clone()); | 1120 | let ty = self.resolve_ty_as_possible(&mut vec![], ty.clone()); |
1157 | return Some(ty); | 1121 | Some(ty) |
1158 | }; | 1122 | } |
1159 | }; | 1123 | Resolution::GenericParam(..) => { |
1160 | 1124 | // generic params can't refer to values... yet | |
1161 | // resolve in module | 1125 | None |
1162 | let typable: Option<TypableDef> = self | 1126 | } |
1163 | .module | 1127 | Resolution::SelfType(_) => { |
1164 | .resolve_path(self.db, &path) | 1128 | log::error!("path expr {:?} resolved to Self type in values ns", path); |
1165 | .take_values()? | 1129 | None |
1166 | .into(); | 1130 | } |
1167 | let typable = typable?; | 1131 | } |
1168 | let ty = self.db.type_for_def(typable); | ||
1169 | let generics = GenericParams::default(); | ||
1170 | let substs = Ty::substs_from_path( | ||
1171 | self.db, | ||
1172 | &self.module, | ||
1173 | self.impl_block.as_ref(), | ||
1174 | &generics, | ||
1175 | path, | ||
1176 | typable, | ||
1177 | ); | ||
1178 | let ty = ty.apply_substs(substs); | ||
1179 | let ty = self.insert_type_vars(ty); | ||
1180 | |||
1181 | Some(ty) | ||
1182 | } | 1132 | } |
1183 | 1133 | ||
1184 | fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option<VariantDef>) { | 1134 | fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option<VariantDef>) { |
@@ -1186,26 +1136,30 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1186 | Some(path) => path, | 1136 | Some(path) => path, |
1187 | None => return (Ty::Unknown, None), | 1137 | None => return (Ty::Unknown, None), |
1188 | }; | 1138 | }; |
1189 | let typable: Option<TypableDef> = self | 1139 | let resolver = &self.resolver; |
1190 | .module | 1140 | let typable: Option<TypableDef> = match resolver.resolve_path(self.db, &path).take_types() { |
1191 | .resolve_path(self.db, &path) | 1141 | Some(Resolution::Def(def)) => def.into(), |
1192 | .take_types() | 1142 | Some(Resolution::LocalBinding(..)) => { |
1193 | .and_then(|it| it.into()); | 1143 | // this cannot happen |
1144 | log::error!("path resolved to local binding in type ns"); | ||
1145 | return (Ty::Unknown, None); | ||
1146 | } | ||
1147 | Some(Resolution::GenericParam(..)) => { | ||
1148 | // generic params can't be used in struct literals | ||
1149 | return (Ty::Unknown, None); | ||
1150 | } | ||
1151 | Some(Resolution::SelfType(..)) => { | ||
1152 | // TODO this is allowed in an impl for a struct, handle this | ||
1153 | return (Ty::Unknown, None); | ||
1154 | } | ||
1155 | None => return (Ty::Unknown, None), | ||
1156 | }; | ||
1194 | let def = match typable { | 1157 | let def = match typable { |
1195 | None => return (Ty::Unknown, None), | 1158 | None => return (Ty::Unknown, None), |
1196 | Some(it) => it, | 1159 | Some(it) => it, |
1197 | }; | 1160 | }; |
1198 | // TODO remove the duplication between here and `Ty::from_path`? | 1161 | // TODO remove the duplication between here and `Ty::from_path`? |
1199 | // TODO provide generics of function | 1162 | let substs = Ty::substs_from_path(self.db, resolver, path, def); |
1200 | let generics = GenericParams::default(); | ||
1201 | let substs = Ty::substs_from_path( | ||
1202 | self.db, | ||
1203 | &self.module, | ||
1204 | self.impl_block.as_ref(), | ||
1205 | &generics, | ||
1206 | path, | ||
1207 | def, | ||
1208 | ); | ||
1209 | match def { | 1163 | match def { |
1210 | TypableDef::Struct(s) => { | 1164 | TypableDef::Struct(s) => { |
1211 | let ty = type_for_struct(self.db, s); | 1165 | let ty = type_for_struct(self.db, s); |
@@ -1303,12 +1257,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1303 | path: ref p, | 1257 | path: ref p, |
1304 | args: ref fields, | 1258 | args: ref fields, |
1305 | } => self.infer_struct_pat(p.as_ref(), fields, expected), | 1259 | } => self.infer_struct_pat(p.as_ref(), fields, expected), |
1306 | Pat::Path(path) => self | 1260 | Pat::Path(path) => { |
1307 | .module | 1261 | // TODO use correct resolver for the surrounding expression |
1308 | .resolve_path(self.db, &path) | 1262 | let resolver = self.resolver.clone(); |
1309 | .take_values() | 1263 | self.infer_path_expr(&resolver, &path) |
1310 | .and_then(|module_def| module_def.into()) | 1264 | .unwrap_or(Ty::Unknown) |
1311 | .map_or(Ty::Unknown, |resolved| self.db.type_for_def(resolved)), | 1265 | } |
1312 | Pat::Bind { | 1266 | Pat::Bind { |
1313 | mode, | 1267 | mode, |
1314 | name: _name, | 1268 | name: _name, |
@@ -1496,7 +1450,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1496 | 1450 | ||
1497 | expected.ty | 1451 | expected.ty |
1498 | } | 1452 | } |
1499 | Expr::Path(p) => self.infer_path_expr(tgt_expr, p).unwrap_or(Ty::Unknown), | 1453 | Expr::Path(p) => { |
1454 | // TODO this could be more efficient... | ||
1455 | let resolver = expr::resolver_for_expr(self.body.clone(), self.db, tgt_expr); | ||
1456 | self.infer_path_expr(&resolver, p).unwrap_or(Ty::Unknown) | ||
1457 | } | ||
1500 | Expr::Continue => Ty::Never, | 1458 | Expr::Continue => Ty::Never, |
1501 | Expr::Break { expr } => { | 1459 | Expr::Break { expr } => { |
1502 | if let Some(expr) = expr { | 1460 | if let Some(expr) = expr { |
@@ -1730,10 +1688,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1730 | pub fn infer(db: &impl HirDatabase, func: Function) -> Arc<InferenceResult> { | 1688 | pub fn infer(db: &impl HirDatabase, func: Function) -> Arc<InferenceResult> { |
1731 | db.check_canceled(); | 1689 | db.check_canceled(); |
1732 | let body = func.body(db); | 1690 | let body = func.body(db); |
1733 | let scopes = db.expr_scopes(func); | 1691 | let resolver = func.resolver(db); |
1734 | let module = func.module(db); | 1692 | let mut ctx = InferenceContext::new(db, body, resolver); |
1735 | let impl_block = func.impl_block(db); | ||
1736 | let mut ctx = InferenceContext::new(db, body, scopes, module, impl_block); | ||
1737 | 1693 | ||
1738 | let signature = func.signature(db); | 1694 | let signature = func.signature(db); |
1739 | ctx.collect_fn_signature(&signature); | 1695 | ctx.collect_fn_signature(&signature); |
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index e857d6856..2282286b0 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -7,12 +7,10 @@ use std::sync::Arc; | |||
7 | use rustc_hash::FxHashMap; | 7 | use rustc_hash::FxHashMap; |
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{ |
10 | HirDatabase, module_tree::ModuleId, Module, ModuleDef, Crate, Name, Function, Trait, | 10 | HirDatabase, module_tree::ModuleId, Module, Crate, Name, Function, Trait, |
11 | ids::TraitId, | 11 | ids::TraitId, |
12 | impl_block::{ImplId, ImplBlock, ImplItem}, | 12 | impl_block::{ImplId, ImplBlock, ImplItem}, |
13 | generics::GenericParams, | ||
14 | ty::{AdtDef, Ty}, | 13 | ty::{AdtDef, Ty}, |
15 | type_ref::TypeRef, | ||
16 | }; | 14 | }; |
17 | 15 | ||
18 | /// This is used as a key for indexing impls. | 16 | /// This is used as a key for indexing impls. |
@@ -85,17 +83,10 @@ impl CrateImplBlocks { | |||
85 | fn collect_recursive(&mut self, db: &impl HirDatabase, module: &Module) { | 83 | fn collect_recursive(&mut self, db: &impl HirDatabase, module: &Module) { |
86 | let module_impl_blocks = db.impls_in_module(module.clone()); | 84 | let module_impl_blocks = db.impls_in_module(module.clone()); |
87 | 85 | ||
88 | for (impl_id, impl_data) in module_impl_blocks.impls.iter() { | 86 | for (impl_id, _) in module_impl_blocks.impls.iter() { |
89 | let impl_block = ImplBlock::from_id(Arc::clone(&module_impl_blocks), impl_id); | 87 | let impl_block = ImplBlock::from_id(Arc::clone(&module_impl_blocks), impl_id); |
90 | // TODO provide generics of impl | 88 | |
91 | let generics = GenericParams::default(); | 89 | let target_ty = impl_block.target_ty(db); |
92 | let target_ty = Ty::from_hir( | ||
93 | db, | ||
94 | &module, | ||
95 | Some(&impl_block), | ||
96 | &generics, | ||
97 | impl_data.target_type(), | ||
98 | ); | ||
99 | 90 | ||
100 | if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) { | 91 | if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) { |
101 | self.impls | 92 | self.impls |
@@ -104,14 +95,11 @@ impl CrateImplBlocks { | |||
104 | .push((module.module_id, impl_id)); | 95 | .push((module.module_id, impl_id)); |
105 | } | 96 | } |
106 | 97 | ||
107 | if let Some(TypeRef::Path(path)) = impl_data.target_trait() { | 98 | if let Some(tr) = impl_block.target_trait(db) { |
108 | let perns = module.resolve_path(db, path); | 99 | self.impls_by_trait |
109 | if let Some(ModuleDef::Trait(tr)) = perns.take_types() { | 100 | .entry(tr.id) |
110 | self.impls_by_trait | 101 | .or_insert_with(Vec::new) |
111 | .entry(tr.id) | 102 | .push((module.module_id, impl_id)); |
112 | .or_insert_with(Vec::new) | ||
113 | .push((module.module_id, impl_id)); | ||
114 | } | ||
115 | } | 103 | } |
116 | } | 104 | } |
117 | 105 | ||
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_function_generics.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_function_generics.snap index 8ff6e55a6..91c48897c 100644 --- a/crates/ra_hir/src/ty/snapshots/tests__infer_function_generics.snap +++ b/crates/ra_hir/src/ty/snapshots/tests__infer_function_generics.snap | |||
@@ -1,12 +1,12 @@ | |||
1 | --- | 1 | --- |
2 | created: "2019-01-26T18:16:16.530712344+00:00" | 2 | created: "2019-01-27T14:52:29.934503829+00:00" |
3 | creator: [email protected] | 3 | creator: [email protected] |
4 | expression: "&result" | 4 | expression: "&result" |
5 | source: crates/ra_hir/src/ty/tests.rs | 5 | source: crates/ra_hir/src/ty/tests.rs |
6 | --- | 6 | --- |
7 | [10; 11) 't': [unknown] | 7 | [10; 11) 't': T |
8 | [21; 26) '{ t }': [unknown] | 8 | [21; 26) '{ t }': T |
9 | [23; 24) 't': [unknown] | 9 | [23; 24) 't': T |
10 | [38; 98) '{ ...(1); }': () | 10 | [38; 98) '{ ...(1); }': () |
11 | [44; 46) 'id': fn id<u32>(T) -> T | 11 | [44; 46) 'id': fn id<u32>(T) -> T |
12 | [44; 52) 'id(1u32)': u32 | 12 | [44; 52) 'id(1u32)': u32 |
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_generic_chain.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_generic_chain.snap index f21bffa75..626f31252 100644 --- a/crates/ra_hir/src/ty/snapshots/tests__infer_generic_chain.snap +++ b/crates/ra_hir/src/ty/snapshots/tests__infer_generic_chain.snap | |||
@@ -1,5 +1,5 @@ | |||
1 | --- | 1 | --- |
2 | created: "2019-01-26T17:46:03.866825843+00:00" | 2 | created: "2019-01-27T14:52:29.938713255+00:00" |
3 | creator: [email protected] | 3 | creator: [email protected] |
4 | expression: "&result" | 4 | expression: "&result" |
5 | source: crates/ra_hir/src/ty/tests.rs | 5 | source: crates/ra_hir/src/ty/tests.rs |
@@ -8,9 +8,9 @@ source: crates/ra_hir/src/ty/tests.rs | |||
8 | [65; 87) '{ ... }': [unknown] | 8 | [65; 87) '{ ... }': [unknown] |
9 | [75; 79) 'self': A<[unknown]> | 9 | [75; 79) 'self': A<[unknown]> |
10 | [75; 81) 'self.x': [unknown] | 10 | [75; 81) 'self.x': [unknown] |
11 | [99; 100) 't': [unknown] | 11 | [99; 100) 't': T |
12 | [110; 115) '{ t }': [unknown] | 12 | [110; 115) '{ t }': T |
13 | [112; 113) 't': [unknown] | 13 | [112; 113) 't': T |
14 | [135; 261) '{ ....x() }': i128 | 14 | [135; 261) '{ ....x() }': i128 |
15 | [146; 147) 'x': i32 | 15 | [146; 147) 'x': i32 |
16 | [150; 151) '1': i32 | 16 | [150; 151) '1': i32 |
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_type_param.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_type_param.snap index a99323264..216d1e41f 100644 --- a/crates/ra_hir/src/ty/snapshots/tests__infer_type_param.snap +++ b/crates/ra_hir/src/ty/snapshots/tests__infer_type_param.snap | |||
@@ -1,15 +1,15 @@ | |||
1 | --- | 1 | --- |
2 | created: "2019-01-27T16:54:18.368427685+00:00" | 2 | created: "2019-01-27T20:38:32.153717698+00:00" |
3 | creator: [email protected] | 3 | creator: [email protected] |
4 | expression: "&result" | 4 | expression: "&result" |
5 | source: crates/ra_hir/src/ty/tests.rs | 5 | source: crates/ra_hir/src/ty/tests.rs |
6 | --- | 6 | --- |
7 | [10; 11) 'x': [unknown] | 7 | [10; 11) 'x': T |
8 | [21; 30) '{ x }': [unknown] | 8 | [21; 30) '{ x }': T |
9 | [27; 28) 'x': [unknown] | 9 | [27; 28) 'x': T |
10 | [44; 45) 'x': &[unknown] | 10 | [44; 45) 'x': &T |
11 | [56; 65) '{ x }': &[unknown] | 11 | [56; 65) '{ x }': &T |
12 | [62; 63) 'x': &[unknown] | 12 | [62; 63) 'x': &T |
13 | [77; 157) '{ ...(1); }': () | 13 | [77; 157) '{ ...(1); }': () |
14 | [87; 88) 'y': u32 | 14 | [87; 88) 'y': u32 |
15 | [91; 96) '10u32': u32 | 15 | [91; 96) '10u32': u32 |
diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs index b33ddcde5..0b9948d4b 100644 --- a/crates/ra_ide_api/src/completion/complete_path.rs +++ b/crates/ra_ide_api/src/completion/complete_path.rs | |||
@@ -1,21 +1,21 @@ | |||
1 | use join_to_string::join; | 1 | use join_to_string::join; |
2 | 2 | ||
3 | use hir::{Docs, Resolution}; | ||
4 | |||
3 | use crate::{ | 5 | use crate::{ |
4 | completion::{CompletionItem, CompletionItemKind, Completions, CompletionKind, CompletionContext}, | 6 | completion::{CompletionItem, CompletionItemKind, Completions, CompletionKind, CompletionContext}, |
5 | }; | 7 | }; |
6 | 8 | ||
7 | use hir::Docs; | ||
8 | |||
9 | pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { | 9 | pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { |
10 | let (path, module) = match (&ctx.path_prefix, &ctx.module) { | 10 | let path = match &ctx.path_prefix { |
11 | (Some(path), Some(module)) => (path.clone(), module), | 11 | Some(path) => path.clone(), |
12 | _ => return, | 12 | _ => return, |
13 | }; | 13 | }; |
14 | let def_id = match module.resolve_path(ctx.db, &path).take_types() { | 14 | let def = match ctx.resolver.resolve_path(ctx.db, &path).take_types() { |
15 | Some(it) => it, | 15 | Some(Resolution::Def(def)) => def, |
16 | None => return, | 16 | _ => return, |
17 | }; | 17 | }; |
18 | match def_id { | 18 | match def { |
19 | hir::ModuleDef::Module(module) => { | 19 | hir::ModuleDef::Module(module) => { |
20 | let module_scope = module.scope(ctx.db); | 20 | let module_scope = module.scope(ctx.db); |
21 | for (name, res) in module_scope.entries() { | 21 | for (name, res) in module_scope.entries() { |
@@ -24,7 +24,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { | |||
24 | ctx.source_range(), | 24 | ctx.source_range(), |
25 | name.to_string(), | 25 | name.to_string(), |
26 | ) | 26 | ) |
27 | .from_resolution(ctx, res) | 27 | .from_resolution(ctx, &res.def.map(hir::Resolution::Def)) |
28 | .add_to(acc); | 28 | .add_to(acc); |
29 | } | 29 | } |
30 | } | 30 | } |
@@ -66,6 +66,17 @@ mod tests { | |||
66 | } | 66 | } |
67 | 67 | ||
68 | #[test] | 68 | #[test] |
69 | #[ignore] // should not complete foo, which currently doesn't work | ||
70 | fn dont_complete_current_use() { | ||
71 | check_reference_completion( | ||
72 | "dont_complete_current_use", | ||
73 | r" | ||
74 | use self::foo<|>; | ||
75 | ", | ||
76 | ); | ||
77 | } | ||
78 | |||
79 | #[test] | ||
69 | fn completes_mod_with_docs() { | 80 | fn completes_mod_with_docs() { |
70 | check_reference_completion( | 81 | check_reference_completion( |
71 | "mod_with_docs", | 82 | "mod_with_docs", |
diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs index f837bb1db..44514ab2b 100644 --- a/crates/ra_ide_api/src/completion/complete_scope.rs +++ b/crates/ra_ide_api/src/completion/complete_scope.rs | |||
@@ -1,63 +1,20 @@ | |||
1 | use rustc_hash::FxHashSet; | 1 | use crate::completion::{CompletionItem, Completions, CompletionKind, CompletionContext}; |
2 | use ra_syntax::ast::AstNode; | ||
3 | use crate::completion::{CompletionItem, CompletionItemKind, Completions, CompletionKind, CompletionContext}; | ||
4 | 2 | ||
5 | pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) { | 3 | pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) { |
6 | if !ctx.is_trivial_path { | 4 | if !ctx.is_trivial_path { |
7 | return; | 5 | return; |
8 | } | 6 | } |
9 | let module = match &ctx.module { | 7 | let names = ctx.resolver.all_names(); |
10 | Some(it) => it, | ||
11 | None => return, | ||
12 | }; | ||
13 | if let Some(function) = &ctx.function { | ||
14 | let scopes = function.scopes(ctx.db); | ||
15 | complete_fn(acc, &scopes, ctx); | ||
16 | } | ||
17 | |||
18 | let module_scope = module.scope(ctx.db); | ||
19 | module_scope | ||
20 | .entries() | ||
21 | .filter(|(_name, res)| { | ||
22 | // For cases like `use self::foo<|>` don't suggest foo itself. | ||
23 | match res.import { | ||
24 | None => true, | ||
25 | Some(import) => { | ||
26 | let source = module.import_source(ctx.db, import); | ||
27 | !source.syntax().range().is_subrange(&ctx.leaf.range()) | ||
28 | } | ||
29 | } | ||
30 | }) | ||
31 | .for_each(|(name, res)| { | ||
32 | CompletionItem::new( | ||
33 | CompletionKind::Reference, | ||
34 | ctx.source_range(), | ||
35 | name.to_string(), | ||
36 | ) | ||
37 | .from_resolution(ctx, res) | ||
38 | .add_to(acc) | ||
39 | }); | ||
40 | } | ||
41 | 8 | ||
42 | fn complete_fn( | 9 | names.into_iter().for_each(|(name, res)| { |
43 | acc: &mut Completions, | 10 | CompletionItem::new( |
44 | scopes: &hir::ScopesWithSyntaxMapping, | 11 | CompletionKind::Reference, |
45 | ctx: &CompletionContext, | 12 | ctx.source_range(), |
46 | ) { | 13 | name.to_string(), |
47 | let mut shadowed = FxHashSet::default(); | 14 | ) |
48 | scopes | 15 | .from_resolution(ctx, &res) |
49 | .scope_chain_for_offset(ctx.offset) | 16 | .add_to(acc) |
50 | .flat_map(|scope| scopes.scopes.entries(scope).iter()) | 17 | }); |
51 | .filter(|entry| shadowed.insert(entry.name())) | ||
52 | .for_each(|entry| { | ||
53 | CompletionItem::new( | ||
54 | CompletionKind::Reference, | ||
55 | ctx.source_range(), | ||
56 | entry.name().to_string(), | ||
57 | ) | ||
58 | .kind(CompletionItemKind::Binding) | ||
59 | .add_to(acc) | ||
60 | }); | ||
61 | } | 18 | } |
62 | 19 | ||
63 | #[cfg(test)] | 20 | #[cfg(test)] |
@@ -116,6 +73,30 @@ mod tests { | |||
116 | } | 73 | } |
117 | 74 | ||
118 | #[test] | 75 | #[test] |
76 | fn completes_generic_params() { | ||
77 | check_reference_completion( | ||
78 | "generic_params", | ||
79 | r" | ||
80 | fn quux<T>() { | ||
81 | <|> | ||
82 | } | ||
83 | ", | ||
84 | ); | ||
85 | } | ||
86 | |||
87 | #[test] | ||
88 | fn completes_generic_params_in_struct() { | ||
89 | check_reference_completion( | ||
90 | "generic_params_in_struct", | ||
91 | r" | ||
92 | struct X<T> { | ||
93 | x: <|> | ||
94 | } | ||
95 | ", | ||
96 | ); | ||
97 | } | ||
98 | |||
99 | #[test] | ||
119 | fn completes_module_items() { | 100 | fn completes_module_items() { |
120 | check_reference_completion( | 101 | check_reference_completion( |
121 | "module_items", | 102 | "module_items", |
@@ -174,5 +155,4 @@ mod tests { | |||
174 | fn completes_self_in_methods() { | 155 | fn completes_self_in_methods() { |
175 | check_reference_completion("self_in_methods", r"impl S { fn foo(&self) { <|> } }") | 156 | check_reference_completion("self_in_methods", r"impl S { fn foo(&self) { <|> } }") |
176 | } | 157 | } |
177 | |||
178 | } | 158 | } |
diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs index 578af6e5b..5d1851da6 100644 --- a/crates/ra_ide_api/src/completion/completion_context.rs +++ b/crates/ra_ide_api/src/completion/completion_context.rs | |||
@@ -5,7 +5,7 @@ use ra_syntax::{ | |||
5 | algo::{find_leaf_at_offset, find_covering_node, find_node_at_offset}, | 5 | algo::{find_leaf_at_offset, find_covering_node, find_node_at_offset}, |
6 | SyntaxKind::*, | 6 | SyntaxKind::*, |
7 | }; | 7 | }; |
8 | use hir::source_binder; | 8 | use hir::{source_binder, Resolver}; |
9 | 9 | ||
10 | use crate::{db, FilePosition}; | 10 | use crate::{db, FilePosition}; |
11 | 11 | ||
@@ -16,6 +16,7 @@ pub(crate) struct CompletionContext<'a> { | |||
16 | pub(super) db: &'a db::RootDatabase, | 16 | pub(super) db: &'a db::RootDatabase, |
17 | pub(super) offset: TextUnit, | 17 | pub(super) offset: TextUnit, |
18 | pub(super) leaf: &'a SyntaxNode, | 18 | pub(super) leaf: &'a SyntaxNode, |
19 | pub(super) resolver: Resolver, | ||
19 | pub(super) module: Option<hir::Module>, | 20 | pub(super) module: Option<hir::Module>, |
20 | pub(super) function: Option<hir::Function>, | 21 | pub(super) function: Option<hir::Function>, |
21 | pub(super) function_syntax: Option<&'a ast::FnDef>, | 22 | pub(super) function_syntax: Option<&'a ast::FnDef>, |
@@ -42,12 +43,14 @@ impl<'a> CompletionContext<'a> { | |||
42 | original_file: &'a SourceFile, | 43 | original_file: &'a SourceFile, |
43 | position: FilePosition, | 44 | position: FilePosition, |
44 | ) -> Option<CompletionContext<'a>> { | 45 | ) -> Option<CompletionContext<'a>> { |
46 | let resolver = source_binder::resolver_for_position(db, position); | ||
45 | let module = source_binder::module_from_position(db, position); | 47 | let module = source_binder::module_from_position(db, position); |
46 | let leaf = find_leaf_at_offset(original_file.syntax(), position.offset).left_biased()?; | 48 | let leaf = find_leaf_at_offset(original_file.syntax(), position.offset).left_biased()?; |
47 | let mut ctx = CompletionContext { | 49 | let mut ctx = CompletionContext { |
48 | db, | 50 | db, |
49 | leaf, | 51 | leaf, |
50 | offset: position.offset, | 52 | offset: position.offset, |
53 | resolver, | ||
51 | module, | 54 | module, |
52 | function: None, | 55 | function: None, |
53 | function_syntax: None, | 56 | function_syntax: None, |
diff --git a/crates/ra_ide_api/src/completion/completion_item.rs b/crates/ra_ide_api/src/completion/completion_item.rs index d3bc14894..bada6a33b 100644 --- a/crates/ra_ide_api/src/completion/completion_item.rs +++ b/crates/ra_ide_api/src/completion/completion_item.rs | |||
@@ -1,5 +1,7 @@ | |||
1 | use hir::{Docs, Documentation}; | 1 | use hir::{Docs, Documentation, PerNs, Resolution}; |
2 | use ra_syntax::TextRange; | 2 | use ra_syntax::{ |
3 | TextRange, | ||
4 | }; | ||
3 | use ra_text_edit::TextEdit; | 5 | use ra_text_edit::TextEdit; |
4 | use test_utils::tested_by; | 6 | use test_utils::tested_by; |
5 | 7 | ||
@@ -48,6 +50,7 @@ pub enum CompletionItemKind { | |||
48 | Trait, | 50 | Trait, |
49 | TypeAlias, | 51 | TypeAlias, |
50 | Method, | 52 | Method, |
53 | TypeParam, | ||
51 | } | 54 | } |
52 | 55 | ||
53 | #[derive(Debug, PartialEq, Eq, Copy, Clone)] | 56 | #[derive(Debug, PartialEq, Eq, Copy, Clone)] |
@@ -207,23 +210,34 @@ impl Builder { | |||
207 | pub(super) fn from_resolution( | 210 | pub(super) fn from_resolution( |
208 | mut self, | 211 | mut self, |
209 | ctx: &CompletionContext, | 212 | ctx: &CompletionContext, |
210 | resolution: &hir::Resolution, | 213 | resolution: &PerNs<Resolution>, |
211 | ) -> Builder { | 214 | ) -> Builder { |
212 | let def = resolution.def.take_types().or(resolution.def.take_values()); | 215 | use hir::ModuleDef::*; |
216 | |||
217 | let def = resolution | ||
218 | .as_ref() | ||
219 | .take_types() | ||
220 | .or(resolution.as_ref().take_values()); | ||
213 | let def = match def { | 221 | let def = match def { |
214 | None => return self, | 222 | None => return self, |
215 | Some(it) => it, | 223 | Some(it) => it, |
216 | }; | 224 | }; |
217 | let (kind, docs) = match def { | 225 | let (kind, docs) = match def { |
218 | hir::ModuleDef::Module(it) => (CompletionItemKind::Module, it.docs(ctx.db)), | 226 | Resolution::Def(Module(it)) => (CompletionItemKind::Module, it.docs(ctx.db)), |
219 | hir::ModuleDef::Function(func) => return self.from_function(ctx, func), | 227 | Resolution::Def(Function(func)) => return self.from_function(ctx, *func), |
220 | hir::ModuleDef::Struct(it) => (CompletionItemKind::Struct, it.docs(ctx.db)), | 228 | Resolution::Def(Struct(it)) => (CompletionItemKind::Struct, it.docs(ctx.db)), |
221 | hir::ModuleDef::Enum(it) => (CompletionItemKind::Enum, it.docs(ctx.db)), | 229 | Resolution::Def(Enum(it)) => (CompletionItemKind::Enum, it.docs(ctx.db)), |
222 | hir::ModuleDef::EnumVariant(it) => (CompletionItemKind::EnumVariant, it.docs(ctx.db)), | 230 | Resolution::Def(EnumVariant(it)) => (CompletionItemKind::EnumVariant, it.docs(ctx.db)), |
223 | hir::ModuleDef::Const(it) => (CompletionItemKind::Const, it.docs(ctx.db)), | 231 | Resolution::Def(Const(it)) => (CompletionItemKind::Const, it.docs(ctx.db)), |
224 | hir::ModuleDef::Static(it) => (CompletionItemKind::Static, it.docs(ctx.db)), | 232 | Resolution::Def(Static(it)) => (CompletionItemKind::Static, it.docs(ctx.db)), |
225 | hir::ModuleDef::Trait(it) => (CompletionItemKind::Trait, it.docs(ctx.db)), | 233 | Resolution::Def(Trait(it)) => (CompletionItemKind::Trait, it.docs(ctx.db)), |
226 | hir::ModuleDef::Type(it) => (CompletionItemKind::TypeAlias, it.docs(ctx.db)), | 234 | Resolution::Def(Type(it)) => (CompletionItemKind::TypeAlias, it.docs(ctx.db)), |
235 | Resolution::GenericParam(..) => (CompletionItemKind::TypeParam, None), | ||
236 | Resolution::LocalBinding(..) => (CompletionItemKind::Binding, None), | ||
237 | Resolution::SelfType(..) => ( | ||
238 | CompletionItemKind::TypeParam, // (does this need its own kind?) | ||
239 | None, | ||
240 | ), | ||
227 | }; | 241 | }; |
228 | self.kind = Some(kind); | 242 | self.kind = Some(kind); |
229 | self.documentation = docs; | 243 | self.documentation = docs; |
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__generic_params.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__generic_params.snap new file mode 100644 index 000000000..71cb55a5b --- /dev/null +++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__generic_params.snap | |||
@@ -0,0 +1,40 @@ | |||
1 | --- | ||
2 | created: "2019-02-01T22:20:40.580128393+00:00" | ||
3 | creator: [email protected] | ||
4 | expression: kind_completions | ||
5 | source: crates/ra_ide_api/src/completion/completion_item.rs | ||
6 | --- | ||
7 | [ | ||
8 | CompletionItem { | ||
9 | completion_kind: Reference, | ||
10 | label: "T", | ||
11 | kind: Some( | ||
12 | TypeParam | ||
13 | ), | ||
14 | detail: None, | ||
15 | documentation: None, | ||
16 | lookup: None, | ||
17 | insert_text: None, | ||
18 | insert_text_format: PlainText, | ||
19 | source_range: [44; 44), | ||
20 | text_edit: None | ||
21 | }, | ||
22 | CompletionItem { | ||
23 | completion_kind: Reference, | ||
24 | label: "quux", | ||
25 | kind: Some( | ||
26 | Function | ||
27 | ), | ||
28 | detail: Some( | ||
29 | "fn quux<T>()" | ||
30 | ), | ||
31 | documentation: None, | ||
32 | lookup: None, | ||
33 | insert_text: Some( | ||
34 | "quux()$0" | ||
35 | ), | ||
36 | insert_text_format: Snippet, | ||
37 | source_range: [44; 44), | ||
38 | text_edit: None | ||
39 | } | ||
40 | ] | ||
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__generic_params_in_struct.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__generic_params_in_struct.snap new file mode 100644 index 000000000..a35c0cd13 --- /dev/null +++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__generic_params_in_struct.snap | |||
@@ -0,0 +1,36 @@ | |||
1 | --- | ||
2 | created: "2019-02-01T22:23:21.508620224+00:00" | ||
3 | creator: [email protected] | ||
4 | expression: kind_completions | ||
5 | source: crates/ra_ide_api/src/completion/completion_item.rs | ||
6 | --- | ||
7 | [ | ||
8 | CompletionItem { | ||
9 | completion_kind: Reference, | ||
10 | label: "T", | ||
11 | kind: Some( | ||
12 | TypeParam | ||
13 | ), | ||
14 | detail: None, | ||
15 | documentation: None, | ||
16 | lookup: None, | ||
17 | insert_text: None, | ||
18 | insert_text_format: PlainText, | ||
19 | source_range: [46; 46), | ||
20 | text_edit: None | ||
21 | }, | ||
22 | CompletionItem { | ||
23 | completion_kind: Reference, | ||
24 | label: "X", | ||
25 | kind: Some( | ||
26 | Struct | ||
27 | ), | ||
28 | detail: None, | ||
29 | documentation: None, | ||
30 | lookup: None, | ||
31 | insert_text: None, | ||
32 | insert_text_format: PlainText, | ||
33 | source_range: [46; 46), | ||
34 | text_edit: None | ||
35 | } | ||
36 | ] | ||
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__self_in_methods.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__self_in_methods.snap index 6a49e325c..ba1d4abbd 100644 --- a/crates/ra_ide_api/src/completion/snapshots/completion_item__self_in_methods.snap +++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__self_in_methods.snap | |||
@@ -1,12 +1,26 @@ | |||
1 | --- | 1 | --- |
2 | created: "2019-01-23T05:27:32.422259+00:00" | 2 | created: "2019-01-27T20:17:10.051725945+00:00" |
3 | creator: insta@0.4.0 | 3 | creator: insta@0.5.2 |
4 | expression: kind_completions | 4 | expression: kind_completions |
5 | source: crates/ra_ide_api/src/completion/completion_item.rs | 5 | source: crates/ra_ide_api/src/completion/completion_item.rs |
6 | --- | 6 | --- |
7 | [ | 7 | [ |
8 | CompletionItem { | 8 | CompletionItem { |
9 | completion_kind: Reference, | 9 | completion_kind: Reference, |
10 | label: "Self", | ||
11 | kind: Some( | ||
12 | TypeParam | ||
13 | ), | ||
14 | detail: None, | ||
15 | documentation: None, | ||
16 | lookup: None, | ||
17 | insert_text: None, | ||
18 | insert_text_format: PlainText, | ||
19 | source_range: [25; 25), | ||
20 | text_edit: None | ||
21 | }, | ||
22 | CompletionItem { | ||
23 | completion_kind: Reference, | ||
10 | label: "self", | 24 | label: "self", |
11 | kind: Some( | 25 | kind: Some( |
12 | Binding | 26 | Binding |
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index 2a20c20ee..88efcea2a 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs | |||
@@ -4,6 +4,7 @@ use ra_syntax::{ | |||
4 | algo::find_node_at_offset, | 4 | algo::find_node_at_offset, |
5 | }; | 5 | }; |
6 | use test_utils::tested_by; | 6 | use test_utils::tested_by; |
7 | use hir::Resolution; | ||
7 | 8 | ||
8 | use crate::{FilePosition, NavigationTarget, db::RootDatabase, RangeInfo}; | 9 | use crate::{FilePosition, NavigationTarget, db::RootDatabase, RangeInfo}; |
9 | 10 | ||
@@ -48,14 +49,7 @@ pub(crate) fn reference_definition( | |||
48 | if let Some(function) = | 49 | if let Some(function) = |
49 | hir::source_binder::function_from_child_node(db, file_id, name_ref.syntax()) | 50 | hir::source_binder::function_from_child_node(db, file_id, name_ref.syntax()) |
50 | { | 51 | { |
51 | let scope = function.scopes(db); | 52 | // Check if it is a method |
52 | // First try to resolve the symbol locally | ||
53 | if let Some(entry) = scope.resolve_local_name(name_ref) { | ||
54 | let nav = NavigationTarget::from_scope_entry(file_id, &entry); | ||
55 | return Exact(nav); | ||
56 | }; | ||
57 | |||
58 | // Next check if it is a method | ||
59 | if let Some(method_call) = name_ref | 53 | if let Some(method_call) = name_ref |
60 | .syntax() | 54 | .syntax() |
61 | .parent() | 55 | .parent() |
@@ -86,19 +80,37 @@ pub(crate) fn reference_definition( | |||
86 | }; | 80 | }; |
87 | } | 81 | } |
88 | } | 82 | } |
89 | // Then try module name resolution | 83 | // Try name resolution |
90 | if let Some(module) = hir::source_binder::module_from_child_node(db, file_id, name_ref.syntax()) | 84 | let resolver = hir::source_binder::resolver_for_node(db, file_id, name_ref.syntax()); |
85 | if let Some(path) = name_ref | ||
86 | .syntax() | ||
87 | .ancestors() | ||
88 | .find_map(ast::Path::cast) | ||
89 | .and_then(hir::Path::from_ast) | ||
91 | { | 90 | { |
92 | if let Some(path) = name_ref | 91 | let resolved = resolver.resolve_path(db, &path); |
93 | .syntax() | 92 | match resolved.clone().take_types().or(resolved.take_values()) { |
94 | .ancestors() | 93 | Some(Resolution::Def(def)) => return Exact(NavigationTarget::from_def(db, def)), |
95 | .find_map(ast::Path::cast) | 94 | Some(Resolution::LocalBinding(pat)) => { |
96 | .and_then(hir::Path::from_ast) | 95 | let body = resolver.body().expect("no body for local binding"); |
97 | { | 96 | let syntax_mapping = body.syntax_mapping(db); |
98 | let resolved = module.resolve_path(db, &path); | 97 | let ptr = syntax_mapping |
99 | if let Some(def_id) = resolved.take_types().or(resolved.take_values()) { | 98 | .pat_syntax(pat) |
100 | return Exact(NavigationTarget::from_def(db, def_id)); | 99 | .expect("pattern not found in syntax mapping"); |
100 | let name = path | ||
101 | .as_ident() | ||
102 | .cloned() | ||
103 | .expect("local binding from a multi-segment path"); | ||
104 | let nav = NavigationTarget::from_scope_entry(file_id, name, ptr); | ||
105 | return Exact(nav); | ||
106 | } | ||
107 | Some(Resolution::GenericParam(..)) => { | ||
108 | // TODO go to the generic param def | ||
109 | } | ||
110 | Some(Resolution::SelfType(_impl_block)) => { | ||
111 | // TODO go to the implemented type | ||
101 | } | 112 | } |
113 | None => {} | ||
102 | } | 114 | } |
103 | } | 115 | } |
104 | // If that fails try the index based approach. | 116 | // If that fails try the index based approach. |
diff --git a/crates/ra_ide_api/src/navigation_target.rs b/crates/ra_ide_api/src/navigation_target.rs index 5ccb5cc2e..617908aed 100644 --- a/crates/ra_ide_api/src/navigation_target.rs +++ b/crates/ra_ide_api/src/navigation_target.rs | |||
@@ -1,9 +1,9 @@ | |||
1 | use ra_db::FileId; | 1 | use ra_db::FileId; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | SyntaxNode, AstNode, SmolStr, TextRange, ast, | 3 | SyntaxNode, SyntaxNodePtr, AstNode, SmolStr, TextRange, ast, |
4 | SyntaxKind::{self, NAME}, | 4 | SyntaxKind::{self, NAME}, |
5 | }; | 5 | }; |
6 | use hir::{ModuleSource, FieldSource}; | 6 | use hir::{ModuleSource, FieldSource, Name}; |
7 | 7 | ||
8 | use crate::{FileSymbol, db::RootDatabase}; | 8 | use crate::{FileSymbol, db::RootDatabase}; |
9 | 9 | ||
@@ -58,12 +58,13 @@ impl NavigationTarget { | |||
58 | 58 | ||
59 | pub(crate) fn from_scope_entry( | 59 | pub(crate) fn from_scope_entry( |
60 | file_id: FileId, | 60 | file_id: FileId, |
61 | entry: &hir::ScopeEntryWithSyntax, | 61 | name: Name, |
62 | ptr: SyntaxNodePtr, | ||
62 | ) -> NavigationTarget { | 63 | ) -> NavigationTarget { |
63 | NavigationTarget { | 64 | NavigationTarget { |
64 | file_id, | 65 | file_id, |
65 | name: entry.name().to_string().into(), | 66 | name: name.to_string().into(), |
66 | full_range: entry.ptr().range(), | 67 | full_range: ptr.range(), |
67 | focus_range: None, | 68 | focus_range: None, |
68 | kind: NAME, | 69 | kind: NAME, |
69 | } | 70 | } |
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs index c033ecdea..17fa07340 100644 --- a/crates/ra_lsp_server/src/conv.rs +++ b/crates/ra_lsp_server/src/conv.rs | |||
@@ -70,6 +70,7 @@ impl Conv for CompletionItemKind { | |||
70 | CompletionItemKind::Const => Constant, | 70 | CompletionItemKind::Const => Constant, |
71 | CompletionItemKind::Static => Value, | 71 | CompletionItemKind::Static => Value, |
72 | CompletionItemKind::Method => Method, | 72 | CompletionItemKind::Method => Method, |
73 | CompletionItemKind::TypeParam => TypeParameter, | ||
73 | } | 74 | } |
74 | } | 75 | } |
75 | } | 76 | } |