diff options
author | Aleksey Kladov <[email protected]> | 2019-04-10 08:46:43 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-04-10 08:48:15 +0100 |
commit | 10726fdb65fda9144a5f9201272d065a268fc1b7 (patch) | |
tree | f5640991cbf0db2bfdad29b911435827cadfb4a8 | |
parent | 1cd184d6539478c7e54c92835902921976dce5d1 (diff) |
type-safer source-map for bindings
-rw-r--r-- | crates/ra_hir/src/either.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir/src/expr.rs | 28 | ||||
-rw-r--r-- | crates/ra_hir/src/expr/scope.rs | 15 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/complete_path.rs | 8 | ||||
-rw-r--r-- | crates/ra_ide_api/src/goto_definition.rs | 1 | ||||
-rw-r--r-- | crates/ra_ide_api/src/references.rs | 11 |
7 files changed, 45 insertions, 30 deletions
diff --git a/crates/ra_hir/src/either.rs b/crates/ra_hir/src/either.rs index 6714529d9..4073cc82e 100644 --- a/crates/ra_hir/src/either.rs +++ b/crates/ra_hir/src/either.rs | |||
@@ -5,6 +5,16 @@ pub enum Either<A, B> { | |||
5 | } | 5 | } |
6 | 6 | ||
7 | impl<A, B> Either<A, B> { | 7 | impl<A, B> Either<A, B> { |
8 | pub fn either<R, F1, F2>(self, f1: F1, f2: F2) -> R | ||
9 | where | ||
10 | F1: FnOnce(A) -> R, | ||
11 | F2: FnOnce(B) -> R, | ||
12 | { | ||
13 | match self { | ||
14 | Either::A(a) => f1(a), | ||
15 | Either::B(b) => f2(b), | ||
16 | } | ||
17 | } | ||
8 | pub fn map<U, V, F1, F2>(self, f1: F1, f2: F2) -> Either<U, V> | 18 | pub fn map<U, V, F1, F2>(self, f1: F1, f2: F2) -> Either<U, V> |
9 | where | 19 | where |
10 | F1: FnOnce(A) -> U, | 20 | F1: FnOnce(A) -> U, |
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 589a9b2db..a2840c15d 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs | |||
@@ -10,7 +10,7 @@ use ra_syntax::{ | |||
10 | }; | 10 | }; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | Path, Name, HirDatabase, Resolver,DefWithBody, | 13 | Path, Name, HirDatabase, Resolver,DefWithBody, Either, |
14 | name::AsName, | 14 | name::AsName, |
15 | type_ref::{Mutability, TypeRef}, | 15 | type_ref::{Mutability, TypeRef}, |
16 | }; | 16 | }; |
@@ -51,11 +51,13 @@ pub struct Body { | |||
51 | pub struct BodySourceMap { | 51 | pub struct BodySourceMap { |
52 | expr_map: FxHashMap<SyntaxNodePtr, ExprId>, | 52 | expr_map: FxHashMap<SyntaxNodePtr, ExprId>, |
53 | expr_map_back: ArenaMap<ExprId, SyntaxNodePtr>, | 53 | expr_map_back: ArenaMap<ExprId, SyntaxNodePtr>, |
54 | pat_map: FxHashMap<SyntaxNodePtr, PatId>, | 54 | pat_map: FxHashMap<PatPrr, PatId>, |
55 | pat_map_back: ArenaMap<PatId, SyntaxNodePtr>, | 55 | pat_map_back: ArenaMap<PatId, PatPrr>, |
56 | field_map: FxHashMap<(ExprId, usize), AstPtr<ast::NamedField>>, | 56 | field_map: FxHashMap<(ExprId, usize), AstPtr<ast::NamedField>>, |
57 | } | 57 | } |
58 | 58 | ||
59 | type PatPrr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; | ||
60 | |||
59 | impl Body { | 61 | impl Body { |
60 | pub fn params(&self) -> &[PatId] { | 62 | pub fn params(&self) -> &[PatId] { |
61 | &self.params | 63 | &self.params |
@@ -127,16 +129,16 @@ impl BodySourceMap { | |||
127 | self.expr_map.get(&SyntaxNodePtr::new(node.syntax())).cloned() | 129 | self.expr_map.get(&SyntaxNodePtr::new(node.syntax())).cloned() |
128 | } | 130 | } |
129 | 131 | ||
130 | pub fn pat_syntax(&self, pat: PatId) -> Option<SyntaxNodePtr> { | 132 | pub fn pat_syntax(&self, pat: PatId) -> Option<PatPrr> { |
131 | self.pat_map_back.get(pat).cloned() | 133 | self.pat_map_back.get(pat).cloned() |
132 | } | 134 | } |
133 | 135 | ||
134 | pub fn syntax_pat(&self, ptr: SyntaxNodePtr) -> Option<PatId> { | 136 | pub fn syntax_pat(&self, ptr: PatPrr) -> Option<PatId> { |
135 | self.pat_map.get(&ptr).cloned() | 137 | self.pat_map.get(&ptr).cloned() |
136 | } | 138 | } |
137 | 139 | ||
138 | pub fn node_pat(&self, node: &ast::Pat) -> Option<PatId> { | 140 | pub fn node_pat(&self, node: &ast::Pat) -> Option<PatId> { |
139 | self.pat_map.get(&SyntaxNodePtr::new(node.syntax())).cloned() | 141 | self.pat_map.get(&Either::A(AstPtr::new(node))).cloned() |
140 | } | 142 | } |
141 | 143 | ||
142 | pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::NamedField> { | 144 | pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::NamedField> { |
@@ -504,10 +506,10 @@ impl ExprCollector { | |||
504 | id | 506 | id |
505 | } | 507 | } |
506 | 508 | ||
507 | fn alloc_pat(&mut self, pat: Pat, syntax_ptr: SyntaxNodePtr) -> PatId { | 509 | fn alloc_pat(&mut self, pat: Pat, ptr: PatPrr) -> PatId { |
508 | let id = self.pats.alloc(pat); | 510 | let id = self.pats.alloc(pat); |
509 | self.source_map.pat_map.insert(syntax_ptr, id); | 511 | self.source_map.pat_map.insert(ptr, id); |
510 | self.source_map.pat_map_back.insert(id, syntax_ptr); | 512 | self.source_map.pat_map_back.insert(id, ptr); |
511 | id | 513 | id |
512 | } | 514 | } |
513 | 515 | ||
@@ -886,8 +888,8 @@ impl ExprCollector { | |||
886 | ast::PatKind::LiteralPat(_) => Pat::Missing, | 888 | ast::PatKind::LiteralPat(_) => Pat::Missing, |
887 | ast::PatKind::SlicePat(_) | ast::PatKind::RangePat(_) => Pat::Missing, | 889 | ast::PatKind::SlicePat(_) | ast::PatKind::RangePat(_) => Pat::Missing, |
888 | }; | 890 | }; |
889 | let syntax_ptr = SyntaxNodePtr::new(pat.syntax()); | 891 | let ptr = AstPtr::new(pat); |
890 | self.alloc_pat(pattern, syntax_ptr) | 892 | self.alloc_pat(pattern, Either::A(ptr)) |
891 | } | 893 | } |
892 | 894 | ||
893 | fn collect_pat_opt(&mut self, pat: Option<&ast::Pat>) -> PatId { | 895 | fn collect_pat_opt(&mut self, pat: Option<&ast::Pat>) -> PatId { |
@@ -911,14 +913,14 @@ impl ExprCollector { | |||
911 | fn collect_fn_body(&mut self, node: &ast::FnDef) { | 913 | fn collect_fn_body(&mut self, node: &ast::FnDef) { |
912 | if let Some(param_list) = node.param_list() { | 914 | if let Some(param_list) = node.param_list() { |
913 | if let Some(self_param) = param_list.self_param() { | 915 | if let Some(self_param) = param_list.self_param() { |
914 | let self_param = SyntaxNodePtr::new(self_param.syntax()); | 916 | let ptr = AstPtr::new(self_param); |
915 | let param_pat = self.alloc_pat( | 917 | let param_pat = self.alloc_pat( |
916 | Pat::Bind { | 918 | Pat::Bind { |
917 | name: Name::self_param(), | 919 | name: Name::self_param(), |
918 | mode: BindingAnnotation::Unannotated, | 920 | mode: BindingAnnotation::Unannotated, |
919 | subpat: None, | 921 | subpat: None, |
920 | }, | 922 | }, |
921 | self_param, | 923 | Either::B(ptr), |
922 | ); | 924 | ); |
923 | self.params.push(param_pat); | 925 | self.params.push(param_pat); |
924 | } | 926 | } |
diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs index f1e6e0f02..725b6c00e 100644 --- a/crates/ra_hir/src/expr/scope.rs +++ b/crates/ra_hir/src/expr/scope.rs | |||
@@ -3,14 +3,14 @@ use std::sync::Arc; | |||
3 | use rustc_hash::{FxHashMap, FxHashSet}; | 3 | use rustc_hash::{FxHashMap, FxHashSet}; |
4 | 4 | ||
5 | use ra_syntax::{ | 5 | use ra_syntax::{ |
6 | AstNode, SyntaxNode, TextUnit, TextRange, SyntaxNodePtr, | 6 | AstNode, SyntaxNode, TextUnit, TextRange, SyntaxNodePtr, AstPtr, |
7 | algo::generate, | 7 | algo::generate, |
8 | ast, | 8 | ast, |
9 | }; | 9 | }; |
10 | use ra_arena::{Arena, RawId, impl_arena_id}; | 10 | use ra_arena::{Arena, RawId, impl_arena_id}; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | Name, AsName,DefWithBody, | 13 | Name, AsName,DefWithBody, Either, |
14 | expr::{PatId, ExprId, Pat, Expr, Body, Statement, BodySourceMap}, | 14 | expr::{PatId, ExprId, Pat, Expr, Body, Statement, BodySourceMap}, |
15 | HirDatabase, | 15 | HirDatabase, |
16 | }; | 16 | }; |
@@ -116,7 +116,7 @@ pub struct ScopesWithSourceMap { | |||
116 | #[derive(Debug, Clone, PartialEq, Eq)] | 116 | #[derive(Debug, Clone, PartialEq, Eq)] |
117 | pub struct ScopeEntryWithSyntax { | 117 | pub struct ScopeEntryWithSyntax { |
118 | name: Name, | 118 | name: Name, |
119 | ptr: SyntaxNodePtr, | 119 | ptr: Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>, |
120 | } | 120 | } |
121 | 121 | ||
122 | impl ScopeEntryWithSyntax { | 122 | impl ScopeEntryWithSyntax { |
@@ -124,7 +124,7 @@ impl ScopeEntryWithSyntax { | |||
124 | &self.name | 124 | &self.name |
125 | } | 125 | } |
126 | 126 | ||
127 | pub fn ptr(&self) -> SyntaxNodePtr { | 127 | pub fn ptr(&self) -> Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>> { |
128 | self.ptr | 128 | self.ptr |
129 | } | 129 | } |
130 | } | 130 | } |
@@ -192,14 +192,14 @@ impl ScopesWithSourceMap { | |||
192 | 192 | ||
193 | pub fn find_all_refs(&self, pat: &ast::BindPat) -> Vec<ReferenceDescriptor> { | 193 | pub fn find_all_refs(&self, pat: &ast::BindPat) -> Vec<ReferenceDescriptor> { |
194 | let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); | 194 | let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); |
195 | let name_ptr = SyntaxNodePtr::new(pat.syntax()); | 195 | let ptr = Either::A(AstPtr::new(pat.into())); |
196 | fn_def | 196 | fn_def |
197 | .syntax() | 197 | .syntax() |
198 | .descendants() | 198 | .descendants() |
199 | .filter_map(ast::NameRef::cast) | 199 | .filter_map(ast::NameRef::cast) |
200 | .filter(|name_ref| match self.resolve_local_name(*name_ref) { | 200 | .filter(|name_ref| match self.resolve_local_name(*name_ref) { |
201 | None => false, | 201 | None => false, |
202 | Some(entry) => entry.ptr() == name_ptr, | 202 | Some(entry) => entry.ptr() == ptr, |
203 | }) | 203 | }) |
204 | .map(|name_ref| ReferenceDescriptor { | 204 | .map(|name_ref| ReferenceDescriptor { |
205 | name: name_ref.syntax().text().to_string(), | 205 | name: name_ref.syntax().text().to_string(), |
@@ -429,7 +429,8 @@ mod tests { | |||
429 | let scopes = | 429 | let scopes = |
430 | ScopesWithSourceMap { scopes: Arc::new(scopes), source_map: Arc::new(source_map) }; | 430 | ScopesWithSourceMap { scopes: Arc::new(scopes), source_map: Arc::new(source_map) }; |
431 | let local_name_entry = scopes.resolve_local_name(name_ref).unwrap(); | 431 | let local_name_entry = scopes.resolve_local_name(name_ref).unwrap(); |
432 | let local_name = local_name_entry.ptr(); | 432 | let local_name = |
433 | local_name_entry.ptr().either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()); | ||
433 | assert_eq!(local_name.range(), expected_name.syntax().range()); | 434 | assert_eq!(local_name.range(), expected_name.syntax().range()); |
434 | } | 435 | } |
435 | 436 | ||
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index f6a325033..ecc63f376 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -2324,7 +2324,7 @@ fn infer(content: &str) -> String { | |||
2324 | 2324 | ||
2325 | for (pat, ty) in inference_result.type_of_pat.iter() { | 2325 | for (pat, ty) in inference_result.type_of_pat.iter() { |
2326 | let syntax_ptr = match body_source_map.pat_syntax(pat) { | 2326 | let syntax_ptr = match body_source_map.pat_syntax(pat) { |
2327 | Some(sp) => sp, | 2327 | Some(sp) => sp.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()), |
2328 | None => continue, | 2328 | None => continue, |
2329 | }; | 2329 | }; |
2330 | types.push((syntax_ptr, ty)); | 2330 | types.push((syntax_ptr, ty)); |
diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs index e54fe7b7e..7e47fa6bd 100644 --- a/crates/ra_ide_api/src/completion/complete_path.rs +++ b/crates/ra_ide_api/src/completion/complete_path.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use hir::Resolution; | 1 | use hir::{Resolution, Either}; |
2 | use ra_syntax::AstNode; | 2 | use ra_syntax::AstNode; |
3 | use test_utils::tested_by; | 3 | use test_utils::tested_by; |
4 | 4 | ||
@@ -19,10 +19,8 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { | |||
19 | for (name, res) in module_scope.entries() { | 19 | for (name, res) in module_scope.entries() { |
20 | if Some(module) == ctx.module { | 20 | if Some(module) == ctx.module { |
21 | if let Some(import) = res.import { | 21 | if let Some(import) = res.import { |
22 | if let hir::ImportSource::UseTree(tree) = | 22 | if let Either::A(use_tree) = module.import_source(ctx.db, import) { |
23 | module.import_source(ctx.db, import) | 23 | if use_tree.syntax().range().contains_inclusive(ctx.offset) { |
24 | { | ||
25 | if tree.syntax().range().contains_inclusive(ctx.offset) { | ||
26 | // for `use self::foo<|>`, don't suggest `foo` as a completion | 24 | // for `use self::foo<|>`, don't suggest `foo` as a completion |
27 | tested_by!(dont_complete_current_use); | 25 | tested_by!(dont_complete_current_use); |
28 | continue; | 26 | continue; |
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index 660b43cfa..60c1f5085 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs | |||
@@ -113,6 +113,7 @@ pub(crate) fn reference_definition( | |||
113 | let ptr = source_map.pat_syntax(pat).expect("pattern not found in syntax mapping"); | 113 | let ptr = source_map.pat_syntax(pat).expect("pattern not found in syntax mapping"); |
114 | let name = | 114 | let name = |
115 | path.as_ident().cloned().expect("local binding from a multi-segment path"); | 115 | path.as_ident().cloned().expect("local binding from a multi-segment path"); |
116 | let ptr = ptr.either(|it| it.into(), |it| it.into()); | ||
116 | let nav = NavigationTarget::from_scope_entry(file_id, name, ptr); | 117 | let nav = NavigationTarget::from_scope_entry(file_id, name, ptr); |
117 | return Exact(nav); | 118 | return Exact(nav); |
118 | } | 119 | } |
diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs index 20bbf11a3..3e30e047c 100644 --- a/crates/ra_ide_api/src/references.rs +++ b/crates/ra_ide_api/src/references.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | use relative_path::{RelativePath, RelativePathBuf}; | 1 | use relative_path::{RelativePath, RelativePathBuf}; |
2 | use hir::{ModuleSource, source_binder}; | 2 | use hir::{ModuleSource, source_binder, Either}; |
3 | use ra_db::{SourceDatabase}; | 3 | use ra_db::{SourceDatabase}; |
4 | use ra_syntax::{ | 4 | use ra_syntax::{ |
5 | AstNode, SyntaxNode, SourceFile, | 5 | AstNode, SyntaxNode, SourceFile, |
@@ -89,9 +89,12 @@ pub(crate) fn find_all_refs( | |||
89 | source_binder::function_from_child_node(db, position.file_id, name_ref.syntax())?; | 89 | source_binder::function_from_child_node(db, position.file_id, name_ref.syntax())?; |
90 | let scope = descr.scopes(db); | 90 | let scope = descr.scopes(db); |
91 | let resolved = scope.resolve_local_name(name_ref)?; | 91 | let resolved = scope.resolve_local_name(name_ref)?; |
92 | let resolved = resolved.ptr().to_node(source_file); | 92 | if let Either::A(ptr) = resolved.ptr() { |
93 | let binding = find_node_at_offset::<ast::BindPat>(syntax, resolved.range().end())?; | 93 | if let ast::PatKind::BindPat(binding) = ptr.to_node(source_file).kind() { |
94 | Some((binding, descr)) | 94 | return Some((binding, descr)); |
95 | } | ||
96 | } | ||
97 | None | ||
95 | } | 98 | } |
96 | } | 99 | } |
97 | 100 | ||