diff options
author | Aleksey Kladov <[email protected]> | 2020-04-26 09:54:08 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-04-26 09:54:08 +0100 |
commit | 05cdc87158ef99d1f59784372ce893596f8a5a80 (patch) | |
tree | c8090164eefa2074005b5d6e36a53b5f78aec1d7 /crates/ra_ide | |
parent | fe99a29ad1226dd3f6801ea4bdb575506324be07 (diff) |
Precompute expected type during completion
Diffstat (limited to 'crates/ra_ide')
-rw-r--r-- | crates/ra_ide/src/completion/complete_unqualified_path.rs | 44 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/completion_context.rs | 33 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/presentation.rs | 2 |
3 files changed, 44 insertions, 35 deletions
diff --git a/crates/ra_ide/src/completion/complete_unqualified_path.rs b/crates/ra_ide/src/completion/complete_unqualified_path.rs index 56cd086c6..f559f2b97 100644 --- a/crates/ra_ide/src/completion/complete_unqualified_path.rs +++ b/crates/ra_ide/src/completion/complete_unqualified_path.rs | |||
@@ -4,7 +4,7 @@ use hir::ScopeDef; | |||
4 | use test_utils::tested_by; | 4 | use test_utils::tested_by; |
5 | 5 | ||
6 | use crate::completion::{CompletionContext, Completions}; | 6 | use crate::completion::{CompletionContext, Completions}; |
7 | use hir::{Adt, ModuleDef}; | 7 | use hir::{Adt, ModuleDef, Type}; |
8 | use ra_syntax::AstNode; | 8 | use ra_syntax::AstNode; |
9 | 9 | ||
10 | pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { | 10 | pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { |
@@ -15,7 +15,9 @@ pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
15 | return; | 15 | return; |
16 | } | 16 | } |
17 | 17 | ||
18 | complete_enum_variants(acc, ctx); | 18 | if let Some(ty) = &ctx.expected_type { |
19 | complete_enum_variants(acc, ctx, ty); | ||
20 | } | ||
19 | 21 | ||
20 | if ctx.is_pat_binding_or_const { | 22 | if ctx.is_pat_binding_or_const { |
21 | return; | 23 | return; |
@@ -34,26 +36,24 @@ pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
34 | }); | 36 | }); |
35 | } | 37 | } |
36 | 38 | ||
37 | fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext) { | 39 | fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) { |
38 | if let Some(ty) = ctx.expected_type_of(&ctx.token.parent()) { | 40 | if let Some(Adt::Enum(enum_data)) = ty.as_adt() { |
39 | if let Some(Adt::Enum(enum_data)) = ty.as_adt() { | 41 | let variants = enum_data.variants(ctx.db); |
40 | let variants = enum_data.variants(ctx.db); | 42 | |
41 | 43 | let module = if let Some(module) = ctx.scope().module() { | |
42 | let module = if let Some(module) = ctx.scope().module() { | 44 | // Compute path from the completion site if available. |
43 | // Compute path from the completion site if available. | 45 | module |
44 | module | 46 | } else { |
45 | } else { | 47 | // Otherwise fall back to the enum's definition site. |
46 | // Otherwise fall back to the enum's definition site. | 48 | enum_data.module(ctx.db) |
47 | enum_data.module(ctx.db) | 49 | }; |
48 | }; | 50 | |
49 | 51 | for variant in variants { | |
50 | for variant in variants { | 52 | if let Some(path) = module.find_use_path(ctx.db, ModuleDef::from(variant)) { |
51 | if let Some(path) = module.find_use_path(ctx.db, ModuleDef::from(variant)) { | 53 | // Variants with trivial paths are already added by the existing completion logic, |
52 | // Variants with trivial paths are already added by the existing completion logic, | 54 | // so we should avoid adding these twice |
53 | // so we should avoid adding these twice | 55 | if path.segments.len() > 1 { |
54 | if path.segments.len() > 1 { | 56 | acc.add_enum_variant(ctx, variant, Some(path.to_string())); |
55 | acc.add_enum_variant(ctx, variant, Some(path.to_string())); | ||
56 | } | ||
57 | } | 57 | } |
58 | } | 58 | } |
59 | } | 59 | } |
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs index 5f2797e41..118fceb2e 100644 --- a/crates/ra_ide/src/completion/completion_context.rs +++ b/crates/ra_ide/src/completion/completion_context.rs | |||
@@ -5,7 +5,7 @@ use ra_db::SourceDatabase; | |||
5 | use ra_ide_db::RootDatabase; | 5 | use ra_ide_db::RootDatabase; |
6 | use ra_syntax::{ | 6 | use ra_syntax::{ |
7 | algo::{find_covering_element, find_node_at_offset}, | 7 | algo::{find_covering_element, find_node_at_offset}, |
8 | ast, AstNode, | 8 | ast, match_ast, AstNode, |
9 | SyntaxKind::*, | 9 | SyntaxKind::*, |
10 | SyntaxNode, SyntaxToken, TextRange, TextSize, | 10 | SyntaxNode, SyntaxToken, TextRange, TextSize, |
11 | }; | 11 | }; |
@@ -26,6 +26,7 @@ pub(crate) struct CompletionContext<'a> { | |||
26 | /// The token before the cursor, in the macro-expanded file. | 26 | /// The token before the cursor, in the macro-expanded file. |
27 | pub(super) token: SyntaxToken, | 27 | pub(super) token: SyntaxToken, |
28 | pub(super) krate: Option<hir::Crate>, | 28 | pub(super) krate: Option<hir::Crate>, |
29 | pub(super) expected_type: Option<Type>, | ||
29 | pub(super) name_ref_syntax: Option<ast::NameRef>, | 30 | pub(super) name_ref_syntax: Option<ast::NameRef>, |
30 | pub(super) function_syntax: Option<ast::FnDef>, | 31 | pub(super) function_syntax: Option<ast::FnDef>, |
31 | pub(super) use_item_syntax: Option<ast::UseItem>, | 32 | pub(super) use_item_syntax: Option<ast::UseItem>, |
@@ -93,6 +94,7 @@ impl<'a> CompletionContext<'a> { | |||
93 | token, | 94 | token, |
94 | offset: position.offset, | 95 | offset: position.offset, |
95 | krate, | 96 | krate, |
97 | expected_type: None, | ||
96 | name_ref_syntax: None, | 98 | name_ref_syntax: None, |
97 | function_syntax: None, | 99 | function_syntax: None, |
98 | use_item_syntax: None, | 100 | use_item_syntax: None, |
@@ -175,23 +177,30 @@ impl<'a> CompletionContext<'a> { | |||
175 | self.sema.scope_at_offset(&self.token.parent(), self.offset) | 177 | self.sema.scope_at_offset(&self.token.parent(), self.offset) |
176 | } | 178 | } |
177 | 179 | ||
178 | pub(crate) fn expected_type_of(&self, node: &SyntaxNode) -> Option<Type> { | ||
179 | for ancestor in node.ancestors() { | ||
180 | if let Some(pat) = ast::Pat::cast(ancestor.clone()) { | ||
181 | return self.sema.type_of_pat(&pat); | ||
182 | } else if let Some(expr) = ast::Expr::cast(ancestor) { | ||
183 | return self.sema.type_of_expr(&expr); | ||
184 | } | ||
185 | } | ||
186 | None | ||
187 | } | ||
188 | |||
189 | fn fill( | 180 | fn fill( |
190 | &mut self, | 181 | &mut self, |
191 | original_file: &SyntaxNode, | 182 | original_file: &SyntaxNode, |
192 | file_with_fake_ident: SyntaxNode, | 183 | file_with_fake_ident: SyntaxNode, |
193 | offset: TextSize, | 184 | offset: TextSize, |
194 | ) { | 185 | ) { |
186 | // FIXME: this is wrong in at least two cases: | ||
187 | // * when there's no token `foo(<|>)` | ||
188 | // * when there is a token, but it happens to have type of it's own | ||
189 | self.expected_type = self | ||
190 | .token | ||
191 | .ancestors() | ||
192 | .find_map(|node| { | ||
193 | let ty = match_ast! { | ||
194 | match node { | ||
195 | ast::Pat(it) => self.sema.type_of_pat(&it), | ||
196 | ast::Expr(it) => self.sema.type_of_expr(&it), | ||
197 | _ => return None, | ||
198 | } | ||
199 | }; | ||
200 | Some(ty) | ||
201 | }) | ||
202 | .flatten(); | ||
203 | |||
195 | // First, let's try to complete a reference to some declaration. | 204 | // First, let's try to complete a reference to some declaration. |
196 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(&file_with_fake_ident, offset) { | 205 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(&file_with_fake_ident, offset) { |
197 | // Special case, `trait T { fn foo(i_am_a_name_ref) {} }`. | 206 | // Special case, `trait T { fn foo(i_am_a_name_ref) {} }`. |
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index f5b074461..77d354376 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs | |||
@@ -351,7 +351,7 @@ impl Builder { | |||
351 | } | 351 | } |
352 | 352 | ||
353 | // Don't add parentheses if the expected type is some function reference. | 353 | // Don't add parentheses if the expected type is some function reference. |
354 | if let Some(ty) = ctx.expected_type_of(&ctx.token.parent()) { | 354 | if let Some(ty) = &ctx.expected_type { |
355 | if ty.is_fn() { | 355 | if ty.is_fn() { |
356 | return self; | 356 | return self; |
357 | } | 357 | } |