Skip to content

Commit ef67e0a

Browse files
bors[bot]matklad
andauthored
Merge #4155
4155: Precompute expected type during completion r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
2 parents d22d88f + 05cdc87 commit ef67e0a

File tree

3 files changed

+44
-35
lines changed

3 files changed

+44
-35
lines changed

crates/ra_ide/src/completion/complete_unqualified_path.rs

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use hir::ScopeDef;
44
use test_utils::tested_by;
55

66
use crate::completion::{CompletionContext, Completions};
7-
use hir::{Adt, ModuleDef};
7+
use hir::{Adt, ModuleDef, Type};
88
use ra_syntax::AstNode;
99

1010
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
1515
return;
1616
}
1717

18-
complete_enum_variants(acc, ctx);
18+
if let Some(ty) = &ctx.expected_type {
19+
complete_enum_variants(acc, ctx, ty);
20+
}
1921

2022
if ctx.is_pat_binding_or_const {
2123
return;
@@ -34,26 +36,24 @@ pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
3436
});
3537
}
3638

37-
fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext) {
38-
if let Some(ty) = ctx.expected_type_of(&ctx.token.parent()) {
39-
if let Some(Adt::Enum(enum_data)) = ty.as_adt() {
40-
let variants = enum_data.variants(ctx.db);
41-
42-
let module = if let Some(module) = ctx.scope().module() {
43-
// Compute path from the completion site if available.
44-
module
45-
} else {
46-
// Otherwise fall back to the enum's definition site.
47-
enum_data.module(ctx.db)
48-
};
49-
50-
for variant in variants {
51-
if let Some(path) = module.find_use_path(ctx.db, ModuleDef::from(variant)) {
52-
// Variants with trivial paths are already added by the existing completion logic,
53-
// so we should avoid adding these twice
54-
if path.segments.len() > 1 {
55-
acc.add_enum_variant(ctx, variant, Some(path.to_string()));
56-
}
39+
fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) {
40+
if let Some(Adt::Enum(enum_data)) = ty.as_adt() {
41+
let variants = enum_data.variants(ctx.db);
42+
43+
let module = if let Some(module) = ctx.scope().module() {
44+
// Compute path from the completion site if available.
45+
module
46+
} else {
47+
// Otherwise fall back to the enum's definition site.
48+
enum_data.module(ctx.db)
49+
};
50+
51+
for variant in variants {
52+
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,
54+
// so we should avoid adding these twice
55+
if path.segments.len() > 1 {
56+
acc.add_enum_variant(ctx, variant, Some(path.to_string()));
5757
}
5858
}
5959
}

crates/ra_ide/src/completion/completion_context.rs

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use ra_db::SourceDatabase;
55
use ra_ide_db::RootDatabase;
66
use ra_syntax::{
77
algo::{find_covering_element, find_node_at_offset},
8-
ast, AstNode,
8+
ast, match_ast, AstNode,
99
SyntaxKind::*,
1010
SyntaxNode, SyntaxToken, TextRange, TextSize,
1111
};
@@ -26,6 +26,7 @@ pub(crate) struct CompletionContext<'a> {
2626
/// The token before the cursor, in the macro-expanded file.
2727
pub(super) token: SyntaxToken,
2828
pub(super) krate: Option<hir::Crate>,
29+
pub(super) expected_type: Option<Type>,
2930
pub(super) name_ref_syntax: Option<ast::NameRef>,
3031
pub(super) function_syntax: Option<ast::FnDef>,
3132
pub(super) use_item_syntax: Option<ast::UseItem>,
@@ -93,6 +94,7 @@ impl<'a> CompletionContext<'a> {
9394
token,
9495
offset: position.offset,
9596
krate,
97+
expected_type: None,
9698
name_ref_syntax: None,
9799
function_syntax: None,
98100
use_item_syntax: None,
@@ -175,23 +177,30 @@ impl<'a> CompletionContext<'a> {
175177
self.sema.scope_at_offset(&self.token.parent(), self.offset)
176178
}
177179

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-
189180
fn fill(
190181
&mut self,
191182
original_file: &SyntaxNode,
192183
file_with_fake_ident: SyntaxNode,
193184
offset: TextSize,
194185
) {
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+
195204
// First, let's try to complete a reference to some declaration.
196205
if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(&file_with_fake_ident, offset) {
197206
// Special case, `trait T { fn foo(i_am_a_name_ref) {} }`.

crates/ra_ide/src/completion/presentation.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ impl Builder {
351351
}
352352

353353
// 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 {
355355
if ty.is_fn() {
356356
return self;
357357
}

0 commit comments

Comments
 (0)