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 | ||
