Prioritize locals with correct types

This commit is contained in:
Aleksey Kladov 2020-05-14 15:15:52 +02:00
parent f1587ac263
commit 90c62bcee9
2 changed files with 55 additions and 5 deletions

View file

@ -34,7 +34,7 @@ pub(crate) struct CompletionContext<'a> {
pub(super) record_pat_syntax: Option<ast::RecordPat>, pub(super) record_pat_syntax: Option<ast::RecordPat>,
pub(super) record_field_syntax: Option<ast::RecordField>, pub(super) record_field_syntax: Option<ast::RecordField>,
pub(super) impl_def: Option<ast::ImplDef>, pub(super) impl_def: Option<ast::ImplDef>,
/// FIXME: `ActiveParameter` is string-based, which is very wrong /// FIXME: `ActiveParameter` is string-based, which is very very wrong
pub(super) active_parameter: Option<ActiveParameter>, pub(super) active_parameter: Option<ActiveParameter>,
pub(super) is_param: bool, pub(super) is_param: bool,
/// If a name-binding or reference to a const in a pattern. /// If a name-binding or reference to a const in a pattern.

View file

@ -17,12 +17,11 @@ use crate::{
impl Completions { impl Completions {
pub(crate) fn add_field(&mut self, ctx: &CompletionContext, field: hir::Field, ty: &Type) { pub(crate) fn add_field(&mut self, ctx: &CompletionContext, field: hir::Field, ty: &Type) {
let is_deprecated = is_deprecated(field, ctx.db); let is_deprecated = is_deprecated(field, ctx.db);
let ty = ty.display(ctx.db).to_string();
let name = field.name(ctx.db); let name = field.name(ctx.db);
let mut completion_item = let mut completion_item =
CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
.kind(CompletionItemKind::Field) .kind(CompletionItemKind::Field)
.detail(ty.clone()) .detail(ty.display(ctx.db).to_string())
.set_documentation(field.docs(ctx.db)) .set_documentation(field.docs(ctx.db))
.set_deprecated(is_deprecated); .set_deprecated(is_deprecated);
@ -107,6 +106,12 @@ impl Completions {
} }
}; };
if let ScopeDef::Local(local) = resolution {
if let Some(score) = compute_score(ctx, &local.ty(ctx.db), &local_name) {
completion_item = completion_item.set_score(score);
}
}
// Add `<>` for generic types // Add `<>` for generic types
if ctx.is_path_type && !ctx.has_type_args && ctx.config.add_call_parenthesis { if ctx.is_path_type && !ctx.has_type_args && ctx.config.add_call_parenthesis {
if let Some(cap) = ctx.config.snippet_cap { if let Some(cap) = ctx.config.snippet_cap {
@ -319,10 +324,11 @@ impl Completions {
pub(crate) fn compute_score( pub(crate) fn compute_score(
ctx: &CompletionContext, ctx: &CompletionContext,
// FIXME: this definitely should be a `Type` ty: &Type,
ty: &str,
name: &str, name: &str,
) -> Option<CompletionScore> { ) -> Option<CompletionScore> {
// FIXME: this should not fall back to string equality.
let ty = &ty.display(ctx.db).to_string();
let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax { let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax {
tested_by!(test_struct_field_completion_in_record_lit); tested_by!(test_struct_field_completion_in_record_lit);
let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?; let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?;
@ -1405,4 +1411,48 @@ mod tests {
"### "###
); );
} }
#[test]
fn prioritize_exact_ref_match() {
assert_debug_snapshot!(
do_reference_completion(
r"
struct WorldSnapshot { _f: () };
fn go(world: &WorldSnapshot) {
go(w<|>)
}
",
),
@r###"
[
CompletionItem {
label: "WorldSnapshot",
source_range: 132..133,
delete: 132..133,
insert: "WorldSnapshot",
kind: Struct,
},
CompletionItem {
label: "go(…)",
source_range: 132..133,
delete: 132..133,
insert: "go(${1:world})$0",
kind: Function,
lookup: "go",
detail: "fn go(world: &WorldSnapshot)",
trigger_call_info: true,
},
CompletionItem {
label: "world",
source_range: 132..133,
delete: 132..133,
insert: "world",
kind: Binding,
detail: "&WorldSnapshot",
score: TypeAndNameMatch,
},
]
"###
);
}
} }