Skip to content

Commit 80dac6a

Browse files
committed
completion relevance distinguish between exact type match and could unify
1 parent 546f8bc commit 80dac6a

File tree

5 files changed

+79
-42
lines changed

5 files changed

+79
-42
lines changed

crates/ide_completion/src/item.rs

+39-20
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ impl fmt::Debug for CompletionItem {
122122
}
123123
}
124124

125-
#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Default)]
125+
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
126126
pub struct CompletionRelevance {
127127
/// This is set in cases like these:
128128
///
@@ -134,31 +134,41 @@ pub struct CompletionRelevance {
134134
/// }
135135
/// ```
136136
pub exact_name_match: bool,
137+
/// See CompletionRelevanceTypeMatch doc comments for cases where this is set.
138+
pub type_match: Option<CompletionRelevanceTypeMatch>,
137139
/// This is set in cases like these:
138140
///
139141
/// ```
140-
/// fn f(spam: String) {}
141-
/// fn main {
142-
/// let foo = String::new();
143-
/// f($0) // type of local matches the type of param
142+
/// fn foo(a: u32) {
143+
/// let b = 0;
144+
/// $0 // `a` and `b` are local
144145
/// }
145146
/// ```
146-
pub exact_type_match: bool,
147+
pub is_local: bool,
148+
}
149+
150+
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
151+
pub enum CompletionRelevanceTypeMatch {
147152
/// This is set in cases like these:
148153
///
149154
/// ```
150-
/// fn foo(bar: u32) {
151-
/// $0 // `bar` is local
155+
/// enum Option<T> { Some(T), None }
156+
/// fn f(a: Option<u32>) {}
157+
/// fn main {
158+
/// f(Option::N$0) // type `Option<T>` could unify with `Option<u32>`
152159
/// }
153160
/// ```
161+
CouldUnify,
162+
/// This is set in cases like these:
154163
///
155164
/// ```
156-
/// fn foo() {
157-
/// let bar = 0;
158-
/// $0 // `bar` is local
165+
/// fn f(spam: String) {}
166+
/// fn main {
167+
/// let foo = String::new();
168+
/// f($0) // type of local matches the type of param
159169
/// }
160170
/// ```
161-
pub is_local: bool,
171+
Exact,
162172
}
163173

164174
impl CompletionRelevance {
@@ -177,9 +187,11 @@ impl CompletionRelevance {
177187
if self.exact_name_match {
178188
score += 1;
179189
}
180-
if self.exact_type_match {
181-
score += 3;
182-
}
190+
score += match self.type_match {
191+
Some(CompletionRelevanceTypeMatch::Exact) => 4,
192+
Some(CompletionRelevanceTypeMatch::CouldUnify) => 3,
193+
None => 0,
194+
};
183195
if self.is_local {
184196
score += 1;
185197
}
@@ -342,7 +354,7 @@ impl CompletionItem {
342354
// match, but with exact type match set because self.ref_match
343355
// is only set if there is an exact type match.
344356
let mut relevance = self.relevance;
345-
relevance.exact_type_match = true;
357+
relevance.type_match = Some(CompletionRelevanceTypeMatch::Exact);
346358

347359
self.ref_match.map(|mutability| (mutability, relevance))
348360
}
@@ -523,7 +535,7 @@ mod tests {
523535
use itertools::Itertools;
524536
use test_utils::assert_eq_text;
525537

526-
use super::CompletionRelevance;
538+
use super::{CompletionRelevance, CompletionRelevanceTypeMatch};
527539

528540
/// Check that these are CompletionRelevance are sorted in ascending order
529541
/// by their relevance score.
@@ -576,15 +588,22 @@ mod tests {
576588
is_local: true,
577589
..CompletionRelevance::default()
578590
}],
579-
vec![CompletionRelevance { exact_type_match: true, ..CompletionRelevance::default() }],
591+
vec![CompletionRelevance {
592+
type_match: Some(CompletionRelevanceTypeMatch::CouldUnify),
593+
..CompletionRelevance::default()
594+
}],
595+
vec![CompletionRelevance {
596+
type_match: Some(CompletionRelevanceTypeMatch::Exact),
597+
..CompletionRelevance::default()
598+
}],
580599
vec![CompletionRelevance {
581600
exact_name_match: true,
582-
exact_type_match: true,
601+
type_match: Some(CompletionRelevanceTypeMatch::Exact),
583602
..CompletionRelevance::default()
584603
}],
585604
vec![CompletionRelevance {
586605
exact_name_match: true,
587-
exact_type_match: true,
606+
type_match: Some(CompletionRelevanceTypeMatch::Exact),
588607
is_local: true,
589608
}],
590609
];

crates/ide_completion/src/render.rs

+37-19
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ use ide_db::{
2020
use syntax::TextRange;
2121

2222
use crate::{
23-
item::ImportEdit, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind,
24-
CompletionRelevance,
23+
item::{CompletionRelevanceTypeMatch, ImportEdit},
24+
CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance,
2525
};
2626

2727
use crate::render::{enum_variant::render_variant, function::render_fn, macro_::render_macro};
@@ -143,7 +143,7 @@ impl<'a> Render<'a> {
143143
.set_deprecated(is_deprecated);
144144

145145
item.set_relevance(CompletionRelevance {
146-
exact_type_match: compute_exact_type_match(self.ctx.completion, ty),
146+
type_match: compute_exact_type_match(self.ctx.completion, ty),
147147
exact_name_match: compute_exact_name_match(self.ctx.completion, name.to_string()),
148148
..CompletionRelevance::default()
149149
});
@@ -243,7 +243,7 @@ impl<'a> Render<'a> {
243243
}
244244

245245
item.set_relevance(CompletionRelevance {
246-
exact_type_match: compute_exact_type_match(self.ctx.completion, &ty),
246+
type_match: compute_exact_type_match(self.ctx.completion, &ty),
247247
exact_name_match: compute_exact_name_match(self.ctx.completion, &local_name),
248248
is_local: true,
249249
..CompletionRelevance::default()
@@ -307,15 +307,24 @@ impl<'a> Render<'a> {
307307
}
308308
}
309309

310-
fn compute_exact_type_match(ctx: &CompletionContext, completion_ty: &hir::Type) -> bool {
311-
match ctx.expected_type.as_ref() {
312-
Some(expected_type) => {
313-
// We don't ever consider unit type to be an exact type match, since
314-
// nearly always this is not meaningful to the user.
315-
(completion_ty == expected_type || expected_type.could_unify_with(completion_ty))
316-
&& !expected_type.is_unit()
317-
}
318-
None => false,
310+
fn compute_exact_type_match(
311+
ctx: &CompletionContext,
312+
completion_ty: &hir::Type,
313+
) -> Option<CompletionRelevanceTypeMatch> {
314+
let expected_type = ctx.expected_type.as_ref()?;
315+
316+
// We don't ever consider unit type to be an exact type match, since
317+
// nearly always this is not meaningful to the user.
318+
if expected_type.is_unit() {
319+
return None;
320+
}
321+
322+
if completion_ty == expected_type {
323+
Some(CompletionRelevanceTypeMatch::Exact)
324+
} else if expected_type.could_unify_with(completion_ty) {
325+
Some(CompletionRelevanceTypeMatch::CouldUnify)
326+
} else {
327+
None
319328
}
320329
}
321330

@@ -347,6 +356,7 @@ mod tests {
347356
use itertools::Itertools;
348357

349358
use crate::{
359+
item::CompletionRelevanceTypeMatch,
350360
test_utils::{check_edit, do_completion, get_all_items, TEST_CONFIG},
351361
CompletionKind, CompletionRelevance,
352362
};
@@ -359,7 +369,11 @@ mod tests {
359369
fn check_relevance(ra_fixture: &str, expect: Expect) {
360370
fn display_relevance(relevance: CompletionRelevance) -> String {
361371
let relevance_factors = vec![
362-
(relevance.exact_type_match, "type"),
372+
(relevance.type_match == Some(CompletionRelevanceTypeMatch::Exact), "type"),
373+
(
374+
relevance.type_match == Some(CompletionRelevanceTypeMatch::CouldUnify),
375+
"type_could_unify",
376+
),
363377
(relevance.exact_name_match, "name"),
364378
(relevance.is_local, "local"),
365379
]
@@ -532,7 +546,9 @@ fn main() { let _: m::Spam = S$0 }
532546
detail: "(i32)",
533547
relevance: CompletionRelevance {
534548
exact_name_match: false,
535-
exact_type_match: true,
549+
type_match: Some(
550+
Exact,
551+
),
536552
is_local: false,
537553
},
538554
trigger_call_info: true,
@@ -558,7 +574,9 @@ fn main() { let _: m::Spam = S$0 }
558574
detail: "()",
559575
relevance: CompletionRelevance {
560576
exact_name_match: false,
561-
exact_type_match: true,
577+
type_match: Some(
578+
Exact,
579+
),
562580
is_local: false,
563581
},
564582
},
@@ -1107,7 +1125,7 @@ fn main() {
11071125
detail: "S",
11081126
relevance: CompletionRelevance {
11091127
exact_name_match: true,
1110-
exact_type_match: false,
1128+
type_match: None,
11111129
is_local: true,
11121130
},
11131131
ref_match: "&mut ",
@@ -1334,8 +1352,8 @@ fn foo() {
13341352
}
13351353
"#,
13361354
expect![[r#"
1337-
ev Foo::A(…) [type]
1338-
ev Foo::B [type]
1355+
ev Foo::A(…) [type_could_unify]
1356+
ev Foo::B [type_could_unify]
13391357
lc foo [type+local]
13401358
en Foo []
13411359
fn baz() []

crates/ide_completion/src/render/enum_variant.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ impl<'a> EnumRender<'a> {
7777

7878
let ty = self.variant.parent_enum(self.ctx.completion.db).ty(self.ctx.completion.db);
7979
item.set_relevance(CompletionRelevance {
80-
exact_type_match: compute_exact_type_match(self.ctx.completion, &ty),
80+
type_match: compute_exact_type_match(self.ctx.completion, &ty),
8181
..CompletionRelevance::default()
8282
});
8383

crates/ide_completion/src/render/function.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ impl<'a> FunctionRender<'a> {
6161

6262
let ret_type = self.func.ret_type(self.ctx.db());
6363
item.set_relevance(CompletionRelevance {
64-
exact_type_match: compute_exact_type_match(self.ctx.completion, &ret_type),
64+
type_match: compute_exact_type_match(self.ctx.completion, &ret_type),
6565
exact_name_match: compute_exact_name_match(self.ctx.completion, self.name.clone()),
6666
..CompletionRelevance::default()
6767
});

crates/rust-analyzer/src/to_proto.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1138,7 +1138,7 @@ mod tests {
11381138
(
11391139
"&arg",
11401140
Some(
1141-
"fffffffa",
1141+
"fffffff9",
11421142
),
11431143
),
11441144
(

0 commit comments

Comments
 (0)