diff options
Diffstat (limited to 'crates/ide_completion')
-rw-r--r-- | crates/ide_completion/src/completions.rs | 2 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/flyimport.rs | 43 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/pattern.rs | 2 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/postfix/format_like.rs | 2 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/qualified_path.rs | 4 | ||||
-rw-r--r-- | crates/ide_completion/src/item.rs | 59 | ||||
-rw-r--r-- | crates/ide_completion/src/lib.rs | 30 | ||||
-rw-r--r-- | crates/ide_completion/src/render.rs | 81 | ||||
-rw-r--r-- | crates/ide_completion/src/render/enum_variant.rs | 4 | ||||
-rw-r--r-- | crates/ide_completion/src/render/function.rs | 4 |
10 files changed, 187 insertions, 44 deletions
diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs index 6d572a836..e2994eed4 100644 --- a/crates/ide_completion/src/completions.rs +++ b/crates/ide_completion/src/completions.rs | |||
@@ -220,7 +220,7 @@ fn complete_enum_variants( | |||
220 | }; | 220 | }; |
221 | 221 | ||
222 | if let Some(impl_) = ctx.impl_def.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) { | 222 | if let Some(impl_) = ctx.impl_def.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) { |
223 | if impl_.target_ty(ctx.db) == *ty { | 223 | if impl_.self_ty(ctx.db) == *ty { |
224 | for &variant in &variants { | 224 | for &variant in &variants { |
225 | let self_path = hir::ModPath::from_segments( | 225 | let self_path = hir::ModPath::from_segments( |
226 | hir::PathKind::Plain, | 226 | hir::PathKind::Plain, |
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs index 1ad017198..9ace13e41 100644 --- a/crates/ide_completion/src/completions/flyimport.rs +++ b/crates/ide_completion/src/completions/flyimport.rs | |||
@@ -113,6 +113,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext) | |||
113 | if ctx.use_item_syntax.is_some() | 113 | if ctx.use_item_syntax.is_some() |
114 | || ctx.attribute_under_caret.is_some() | 114 | || ctx.attribute_under_caret.is_some() |
115 | || ctx.mod_declaration_under_caret.is_some() | 115 | || ctx.mod_declaration_under_caret.is_some() |
116 | || ctx.record_lit_syntax.is_some() | ||
116 | { | 117 | { |
117 | return None; | 118 | return None; |
118 | } | 119 | } |
@@ -1034,4 +1035,46 @@ fn main() { | |||
1034 | expect![[]], | 1035 | expect![[]], |
1035 | ); | 1036 | ); |
1036 | } | 1037 | } |
1038 | |||
1039 | #[test] | ||
1040 | fn no_fuzzy_during_fields_of_record_lit_syntax() { | ||
1041 | check( | ||
1042 | r#" | ||
1043 | mod m { | ||
1044 | pub fn some_fn() -> i32 { | ||
1045 | 42 | ||
1046 | } | ||
1047 | } | ||
1048 | struct Foo { | ||
1049 | some_field: i32, | ||
1050 | } | ||
1051 | fn main() { | ||
1052 | let _ = Foo { so$0 }; | ||
1053 | } | ||
1054 | "#, | ||
1055 | expect![[]], | ||
1056 | ); | ||
1057 | } | ||
1058 | |||
1059 | #[test] | ||
1060 | fn fuzzy_after_fields_of_record_lit_syntax() { | ||
1061 | check( | ||
1062 | r#" | ||
1063 | mod m { | ||
1064 | pub fn some_fn() -> i32 { | ||
1065 | 42 | ||
1066 | } | ||
1067 | } | ||
1068 | struct Foo { | ||
1069 | some_field: i32, | ||
1070 | } | ||
1071 | fn main() { | ||
1072 | let _ = Foo { some_field: so$0 }; | ||
1073 | } | ||
1074 | "#, | ||
1075 | expect![[r#" | ||
1076 | fn some_fn() (m::some_fn) fn() -> i32 | ||
1077 | "#]], | ||
1078 | ); | ||
1079 | } | ||
1037 | } | 1080 | } |
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs index b06498e6d..808d7ff7e 100644 --- a/crates/ide_completion/src/completions/pattern.rs +++ b/crates/ide_completion/src/completions/pattern.rs | |||
@@ -40,7 +40,7 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | |||
40 | _ => false, | 40 | _ => false, |
41 | }, | 41 | }, |
42 | hir::ScopeDef::MacroDef(_) => true, | 42 | hir::ScopeDef::MacroDef(_) => true, |
43 | hir::ScopeDef::ImplSelfType(impl_) => match impl_.target_ty(ctx.db).as_adt() { | 43 | hir::ScopeDef::ImplSelfType(impl_) => match impl_.self_ty(ctx.db).as_adt() { |
44 | Some(hir::Adt::Struct(strukt)) => { | 44 | Some(hir::Adt::Struct(strukt)) => { |
45 | acc.add_struct_pat(ctx, strukt, Some(name.clone())); | 45 | acc.add_struct_pat(ctx, strukt, Some(name.clone())); |
46 | true | 46 | true |
diff --git a/crates/ide_completion/src/completions/postfix/format_like.rs b/crates/ide_completion/src/completions/postfix/format_like.rs index 3f1c6730b..e86ffa8f8 100644 --- a/crates/ide_completion/src/completions/postfix/format_like.rs +++ b/crates/ide_completion/src/completions/postfix/format_like.rs | |||
@@ -13,6 +13,8 @@ | |||
13 | // + `logi` -> `log::info!(...)` | 13 | // + `logi` -> `log::info!(...)` |
14 | // + `logw` -> `log::warn!(...)` | 14 | // + `logw` -> `log::warn!(...)` |
15 | // + `loge` -> `log::error!(...)` | 15 | // + `loge` -> `log::error!(...)` |
16 | // | ||
17 | // image::https://user-images.githubusercontent.com/48062697/113020656-b560f500-917a-11eb-87de-02991f61beb8.gif[] | ||
16 | 18 | ||
17 | use ide_db::helpers::SnippetCap; | 19 | use ide_db::helpers::SnippetCap; |
18 | use syntax::ast::{self, AstToken}; | 20 | use syntax::ast::{self, AstToken}; |
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs index 105ff6013..969249df6 100644 --- a/crates/ide_completion/src/completions/qualified_path.rs +++ b/crates/ide_completion/src/completions/qualified_path.rs | |||
@@ -24,7 +24,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
24 | }; | 24 | }; |
25 | 25 | ||
26 | // Add associated types on type parameters and `Self`. | 26 | // Add associated types on type parameters and `Self`. |
27 | resolution.assoc_type_shorthand_candidates(ctx.db, |alias| { | 27 | resolution.assoc_type_shorthand_candidates(ctx.db, |_, alias| { |
28 | acc.add_type_alias(ctx, alias); | 28 | acc.add_type_alias(ctx, alias); |
29 | None::<()> | 29 | None::<()> |
30 | }); | 30 | }); |
@@ -117,7 +117,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
117 | if let Some(krate) = ctx.krate { | 117 | if let Some(krate) = ctx.krate { |
118 | let ty = match resolution { | 118 | let ty = match resolution { |
119 | PathResolution::TypeParam(param) => param.ty(ctx.db), | 119 | PathResolution::TypeParam(param) => param.ty(ctx.db), |
120 | PathResolution::SelfType(impl_def) => impl_def.target_ty(ctx.db), | 120 | PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db), |
121 | _ => return, | 121 | _ => return, |
122 | }; | 122 | }; |
123 | 123 | ||
diff --git a/crates/ide_completion/src/item.rs b/crates/ide_completion/src/item.rs index 9a4b5217a..cc4ac9ea2 100644 --- a/crates/ide_completion/src/item.rs +++ b/crates/ide_completion/src/item.rs | |||
@@ -122,7 +122,7 @@ impl fmt::Debug for CompletionItem { | |||
122 | } | 122 | } |
123 | } | 123 | } |
124 | 124 | ||
125 | #[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Default)] | 125 | #[derive(Debug, Clone, Copy, Eq, PartialEq, Default)] |
126 | pub struct CompletionRelevance { | 126 | pub struct CompletionRelevance { |
127 | /// This is set in cases like these: | 127 | /// This is set in cases like these: |
128 | /// | 128 | /// |
@@ -134,31 +134,41 @@ pub struct CompletionRelevance { | |||
134 | /// } | 134 | /// } |
135 | /// ``` | 135 | /// ``` |
136 | pub exact_name_match: bool, | 136 | pub exact_name_match: bool, |
137 | /// See CompletionRelevanceTypeMatch doc comments for cases where this is set. | ||
138 | pub type_match: Option<CompletionRelevanceTypeMatch>, | ||
137 | /// This is set in cases like these: | 139 | /// This is set in cases like these: |
138 | /// | 140 | /// |
139 | /// ``` | 141 | /// ``` |
140 | /// fn f(spam: String) {} | 142 | /// fn foo(a: u32) { |
141 | /// fn main { | 143 | /// let b = 0; |
142 | /// let foo = String::new(); | 144 | /// $0 // `a` and `b` are local |
143 | /// f($0) // type of local matches the type of param | ||
144 | /// } | 145 | /// } |
145 | /// ``` | 146 | /// ``` |
146 | pub exact_type_match: bool, | 147 | pub is_local: bool, |
148 | } | ||
149 | |||
150 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] | ||
151 | pub enum CompletionRelevanceTypeMatch { | ||
147 | /// This is set in cases like these: | 152 | /// This is set in cases like these: |
148 | /// | 153 | /// |
149 | /// ``` | 154 | /// ``` |
150 | /// fn foo(bar: u32) { | 155 | /// enum Option<T> { Some(T), None } |
151 | /// $0 // `bar` is local | 156 | /// fn f(a: Option<u32>) {} |
157 | /// fn main { | ||
158 | /// f(Option::N$0) // type `Option<T>` could unify with `Option<u32>` | ||
152 | /// } | 159 | /// } |
153 | /// ``` | 160 | /// ``` |
161 | CouldUnify, | ||
162 | /// This is set in cases like these: | ||
154 | /// | 163 | /// |
155 | /// ``` | 164 | /// ``` |
156 | /// fn foo() { | 165 | /// fn f(spam: String) {} |
157 | /// let bar = 0; | 166 | /// fn main { |
158 | /// $0 // `bar` is local | 167 | /// let foo = String::new(); |
168 | /// f($0) // type of local matches the type of param | ||
159 | /// } | 169 | /// } |
160 | /// ``` | 170 | /// ``` |
161 | pub is_local: bool, | 171 | Exact, |
162 | } | 172 | } |
163 | 173 | ||
164 | impl CompletionRelevance { | 174 | impl CompletionRelevance { |
@@ -177,9 +187,11 @@ impl CompletionRelevance { | |||
177 | if self.exact_name_match { | 187 | if self.exact_name_match { |
178 | score += 1; | 188 | score += 1; |
179 | } | 189 | } |
180 | if self.exact_type_match { | 190 | score += match self.type_match { |
181 | score += 3; | 191 | Some(CompletionRelevanceTypeMatch::Exact) => 4, |
182 | } | 192 | Some(CompletionRelevanceTypeMatch::CouldUnify) => 3, |
193 | None => 0, | ||
194 | }; | ||
183 | if self.is_local { | 195 | if self.is_local { |
184 | score += 1; | 196 | score += 1; |
185 | } | 197 | } |
@@ -342,7 +354,7 @@ impl CompletionItem { | |||
342 | // match, but with exact type match set because self.ref_match | 354 | // match, but with exact type match set because self.ref_match |
343 | // is only set if there is an exact type match. | 355 | // is only set if there is an exact type match. |
344 | let mut relevance = self.relevance; | 356 | let mut relevance = self.relevance; |
345 | relevance.exact_type_match = true; | 357 | relevance.type_match = Some(CompletionRelevanceTypeMatch::Exact); |
346 | 358 | ||
347 | self.ref_match.map(|mutability| (mutability, relevance)) | 359 | self.ref_match.map(|mutability| (mutability, relevance)) |
348 | } | 360 | } |
@@ -523,7 +535,7 @@ mod tests { | |||
523 | use itertools::Itertools; | 535 | use itertools::Itertools; |
524 | use test_utils::assert_eq_text; | 536 | use test_utils::assert_eq_text; |
525 | 537 | ||
526 | use super::CompletionRelevance; | 538 | use super::{CompletionRelevance, CompletionRelevanceTypeMatch}; |
527 | 539 | ||
528 | /// Check that these are CompletionRelevance are sorted in ascending order | 540 | /// Check that these are CompletionRelevance are sorted in ascending order |
529 | /// by their relevance score. | 541 | /// by their relevance score. |
@@ -576,15 +588,22 @@ mod tests { | |||
576 | is_local: true, | 588 | is_local: true, |
577 | ..CompletionRelevance::default() | 589 | ..CompletionRelevance::default() |
578 | }], | 590 | }], |
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 | }], | ||
580 | vec![CompletionRelevance { | 599 | vec![CompletionRelevance { |
581 | exact_name_match: true, | 600 | exact_name_match: true, |
582 | exact_type_match: true, | 601 | type_match: Some(CompletionRelevanceTypeMatch::Exact), |
583 | ..CompletionRelevance::default() | 602 | ..CompletionRelevance::default() |
584 | }], | 603 | }], |
585 | vec![CompletionRelevance { | 604 | vec![CompletionRelevance { |
586 | exact_name_match: true, | 605 | exact_name_match: true, |
587 | exact_type_match: true, | 606 | type_match: Some(CompletionRelevanceTypeMatch::Exact), |
588 | is_local: true, | 607 | is_local: true, |
589 | }], | 608 | }], |
590 | ]; | 609 | ]; |
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs index 5ac1cb48d..6f3d5c5c5 100644 --- a/crates/ide_completion/src/lib.rs +++ b/crates/ide_completion/src/lib.rs | |||
@@ -81,6 +81,8 @@ pub use crate::{ | |||
81 | // And the auto import completions, enabled with the `rust-analyzer.completion.autoimport.enable` setting and the corresponding LSP client capabilities. | 81 | // And the auto import completions, enabled with the `rust-analyzer.completion.autoimport.enable` setting and the corresponding LSP client capabilities. |
82 | // Those are the additional completion options with automatic `use` import and options from all project importable items, | 82 | // Those are the additional completion options with automatic `use` import and options from all project importable items, |
83 | // fuzzy matched agains the completion imput. | 83 | // fuzzy matched agains the completion imput. |
84 | // | ||
85 | // image::https://user-images.githubusercontent.com/48062697/113020667-b72ab880-917a-11eb-8778-716cf26a0eb3.gif[] | ||
84 | 86 | ||
85 | /// Main entry point for completion. We run completion as a two-phase process. | 87 | /// Main entry point for completion. We run completion as a two-phase process. |
86 | /// | 88 | /// |
@@ -104,6 +106,34 @@ pub use crate::{ | |||
104 | /// `foo` *should* be present among the completion variants. Filtering by | 106 | /// `foo` *should* be present among the completion variants. Filtering by |
105 | /// identifier prefix/fuzzy match should be done higher in the stack, together | 107 | /// identifier prefix/fuzzy match should be done higher in the stack, together |
106 | /// with ordering of completions (currently this is done by the client). | 108 | /// with ordering of completions (currently this is done by the client). |
109 | /// | ||
110 | /// # Hypothetical Completion Problem | ||
111 | /// | ||
112 | /// There's a curious unsolved problem in the current implementation. Often, you | ||
113 | /// want to compute completions on a *slightly different* text document. | ||
114 | /// | ||
115 | /// In the simplest case, when the code looks like `let x = `, you want to | ||
116 | /// insert a fake identifier to get a better syntax tree: `let x = complete_me`. | ||
117 | /// | ||
118 | /// We do this in `CompletionContext`, and it works OK-enough for *syntax* | ||
119 | /// analysis. However, we might want to, eg, ask for the type of `complete_me` | ||
120 | /// variable, and that's where our current infrastructure breaks down. salsa | ||
121 | /// doesn't allow such "phantom" inputs. | ||
122 | /// | ||
123 | /// Another case where this would be instrumental is macro expansion. We want to | ||
124 | /// insert a fake ident and re-expand code. There's `expand_hypothetical` as a | ||
125 | /// work-around for this. | ||
126 | /// | ||
127 | /// A different use-case is completion of injection (examples and links in doc | ||
128 | /// comments). When computing completion for a path in a doc-comment, you want | ||
129 | /// to inject a fake path expression into the item being documented and complete | ||
130 | /// that. | ||
131 | /// | ||
132 | /// IntelliJ has CodeFragment/Context infrastructure for that. You can create a | ||
133 | /// temporary PSI node, and say that the context ("parent") of this node is some | ||
134 | /// existing node. Asking for, eg, type of this `CodeFragment` node works | ||
135 | /// correctly, as the underlying infrastructure makes use of contexts to do | ||
136 | /// analysis. | ||
107 | pub fn completions( | 137 | pub fn completions( |
108 | db: &RootDatabase, | 138 | db: &RootDatabase, |
109 | config: &CompletionConfig, | 139 | config: &CompletionConfig, |
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index 9ce49074f..1a762d3dc 100644 --- a/crates/ide_completion/src/render.rs +++ b/crates/ide_completion/src/render.rs | |||
@@ -20,8 +20,8 @@ use ide_db::{ | |||
20 | use syntax::TextRange; | 20 | use syntax::TextRange; |
21 | 21 | ||
22 | use crate::{ | 22 | use crate::{ |
23 | item::ImportEdit, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, | 23 | item::{CompletionRelevanceTypeMatch, ImportEdit}, |
24 | CompletionRelevance, | 24 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, |
25 | }; | 25 | }; |
26 | 26 | ||
27 | use crate::render::{enum_variant::render_variant, function::render_fn, macro_::render_macro}; | 27 | use crate::render::{enum_variant::render_variant, function::render_fn, macro_::render_macro}; |
@@ -143,7 +143,7 @@ impl<'a> Render<'a> { | |||
143 | .set_deprecated(is_deprecated); | 143 | .set_deprecated(is_deprecated); |
144 | 144 | ||
145 | item.set_relevance(CompletionRelevance { | 145 | item.set_relevance(CompletionRelevance { |
146 | exact_type_match: compute_exact_type_match(self.ctx.completion, ty), | 146 | type_match: compute_type_match(self.ctx.completion, ty), |
147 | exact_name_match: compute_exact_name_match(self.ctx.completion, name.to_string()), | 147 | exact_name_match: compute_exact_name_match(self.ctx.completion, name.to_string()), |
148 | ..CompletionRelevance::default() | 148 | ..CompletionRelevance::default() |
149 | }); | 149 | }); |
@@ -245,7 +245,7 @@ impl<'a> Render<'a> { | |||
245 | } | 245 | } |
246 | 246 | ||
247 | item.set_relevance(CompletionRelevance { | 247 | item.set_relevance(CompletionRelevance { |
248 | exact_type_match: compute_exact_type_match(self.ctx.completion, &ty), | 248 | type_match: compute_type_match(self.ctx.completion, &ty), |
249 | exact_name_match: compute_exact_name_match(self.ctx.completion, &local_name), | 249 | exact_name_match: compute_exact_name_match(self.ctx.completion, &local_name), |
250 | is_local: true, | 250 | is_local: true, |
251 | ..CompletionRelevance::default() | 251 | ..CompletionRelevance::default() |
@@ -309,14 +309,24 @@ impl<'a> Render<'a> { | |||
309 | } | 309 | } |
310 | } | 310 | } |
311 | 311 | ||
312 | fn compute_exact_type_match(ctx: &CompletionContext, completion_ty: &hir::Type) -> bool { | 312 | fn compute_type_match( |
313 | match ctx.expected_type.as_ref() { | 313 | ctx: &CompletionContext, |
314 | Some(expected_type) => { | 314 | completion_ty: &hir::Type, |
315 | // We don't ever consider unit type to be an exact type match, since | 315 | ) -> Option<CompletionRelevanceTypeMatch> { |
316 | // nearly always this is not meaningful to the user. | 316 | let expected_type = ctx.expected_type.as_ref()?; |
317 | completion_ty == expected_type && !expected_type.is_unit() | 317 | |
318 | } | 318 | // We don't ever consider unit type to be an exact type match, since |
319 | None => false, | 319 | // nearly always this is not meaningful to the user. |
320 | if expected_type.is_unit() { | ||
321 | return None; | ||
322 | } | ||
323 | |||
324 | if completion_ty == expected_type { | ||
325 | Some(CompletionRelevanceTypeMatch::Exact) | ||
326 | } else if expected_type.could_unify_with(completion_ty) { | ||
327 | Some(CompletionRelevanceTypeMatch::CouldUnify) | ||
328 | } else { | ||
329 | None | ||
320 | } | 330 | } |
321 | } | 331 | } |
322 | 332 | ||
@@ -348,6 +358,7 @@ mod tests { | |||
348 | use itertools::Itertools; | 358 | use itertools::Itertools; |
349 | 359 | ||
350 | use crate::{ | 360 | use crate::{ |
361 | item::CompletionRelevanceTypeMatch, | ||
351 | test_utils::{check_edit, do_completion, get_all_items, TEST_CONFIG}, | 362 | test_utils::{check_edit, do_completion, get_all_items, TEST_CONFIG}, |
352 | CompletionKind, CompletionRelevance, | 363 | CompletionKind, CompletionRelevance, |
353 | }; | 364 | }; |
@@ -360,7 +371,11 @@ mod tests { | |||
360 | fn check_relevance(ra_fixture: &str, expect: Expect) { | 371 | fn check_relevance(ra_fixture: &str, expect: Expect) { |
361 | fn display_relevance(relevance: CompletionRelevance) -> String { | 372 | fn display_relevance(relevance: CompletionRelevance) -> String { |
362 | let relevance_factors = vec![ | 373 | let relevance_factors = vec![ |
363 | (relevance.exact_type_match, "type"), | 374 | (relevance.type_match == Some(CompletionRelevanceTypeMatch::Exact), "type"), |
375 | ( | ||
376 | relevance.type_match == Some(CompletionRelevanceTypeMatch::CouldUnify), | ||
377 | "type_could_unify", | ||
378 | ), | ||
364 | (relevance.exact_name_match, "name"), | 379 | (relevance.exact_name_match, "name"), |
365 | (relevance.is_local, "local"), | 380 | (relevance.is_local, "local"), |
366 | ] | 381 | ] |
@@ -533,7 +548,9 @@ fn main() { let _: m::Spam = S$0 } | |||
533 | detail: "(i32)", | 548 | detail: "(i32)", |
534 | relevance: CompletionRelevance { | 549 | relevance: CompletionRelevance { |
535 | exact_name_match: false, | 550 | exact_name_match: false, |
536 | exact_type_match: true, | 551 | type_match: Some( |
552 | Exact, | ||
553 | ), | ||
537 | is_local: false, | 554 | is_local: false, |
538 | }, | 555 | }, |
539 | trigger_call_info: true, | 556 | trigger_call_info: true, |
@@ -559,7 +576,9 @@ fn main() { let _: m::Spam = S$0 } | |||
559 | detail: "()", | 576 | detail: "()", |
560 | relevance: CompletionRelevance { | 577 | relevance: CompletionRelevance { |
561 | exact_name_match: false, | 578 | exact_name_match: false, |
562 | exact_type_match: true, | 579 | type_match: Some( |
580 | Exact, | ||
581 | ), | ||
563 | is_local: false, | 582 | is_local: false, |
564 | }, | 583 | }, |
565 | }, | 584 | }, |
@@ -1108,7 +1127,7 @@ fn main() { | |||
1108 | detail: "S", | 1127 | detail: "S", |
1109 | relevance: CompletionRelevance { | 1128 | relevance: CompletionRelevance { |
1110 | exact_name_match: true, | 1129 | exact_name_match: true, |
1111 | exact_type_match: false, | 1130 | type_match: None, |
1112 | is_local: true, | 1131 | is_local: true, |
1113 | }, | 1132 | }, |
1114 | ref_match: "&mut ", | 1133 | ref_match: "&mut ", |
@@ -1353,4 +1372,34 @@ fn foo(f: Foo) { let _: &u32 = f.b$0 } | |||
1353 | "#]], | 1372 | "#]], |
1354 | ); | 1373 | ); |
1355 | } | 1374 | } |
1375 | |||
1376 | #[test] | ||
1377 | fn generic_enum() { | ||
1378 | check_relevance( | ||
1379 | r#" | ||
1380 | enum Foo<T> { A(T), B } | ||
1381 | // bar() should not be an exact type match | ||
1382 | // because the generic parameters are different | ||
1383 | fn bar() -> Foo<u8> { Foo::B } | ||
1384 | // FIXME baz() should be an exact type match | ||
1385 | // because the types could unify, but it currently | ||
1386 | // is not. This is due to the T here being | ||
1387 | // TyKind::Placeholder rather than TyKind::Missing. | ||
1388 | fn baz<T>() -> Foo<T> { Foo::B } | ||
1389 | fn foo() { | ||
1390 | let foo: Foo<u32> = Foo::B; | ||
1391 | let _: Foo<u32> = f$0; | ||
1392 | } | ||
1393 | "#, | ||
1394 | expect![[r#" | ||
1395 | ev Foo::A(…) [type_could_unify] | ||
1396 | ev Foo::B [type_could_unify] | ||
1397 | lc foo [type+local] | ||
1398 | en Foo [] | ||
1399 | fn baz() [] | ||
1400 | fn bar() [] | ||
1401 | fn foo() [] | ||
1402 | "#]], | ||
1403 | ); | ||
1404 | } | ||
1356 | } | 1405 | } |
diff --git a/crates/ide_completion/src/render/enum_variant.rs b/crates/ide_completion/src/render/enum_variant.rs index 374247b05..832f5ced1 100644 --- a/crates/ide_completion/src/render/enum_variant.rs +++ b/crates/ide_completion/src/render/enum_variant.rs | |||
@@ -6,7 +6,7 @@ use itertools::Itertools; | |||
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
8 | item::{CompletionItem, CompletionKind, ImportEdit}, | 8 | item::{CompletionItem, CompletionKind, ImportEdit}, |
9 | render::{builder_ext::Params, compute_exact_type_match, compute_ref_match, RenderContext}, | 9 | render::{builder_ext::Params, compute_ref_match, compute_type_match, RenderContext}, |
10 | CompletionRelevance, | 10 | CompletionRelevance, |
11 | }; | 11 | }; |
12 | 12 | ||
@@ -77,7 +77,7 @@ impl<'a> EnumRender<'a> { | |||
77 | 77 | ||
78 | let ty = self.variant.parent_enum(self.ctx.completion.db).ty(self.ctx.completion.db); | 78 | let ty = self.variant.parent_enum(self.ctx.completion.db).ty(self.ctx.completion.db); |
79 | item.set_relevance(CompletionRelevance { | 79 | item.set_relevance(CompletionRelevance { |
80 | exact_type_match: compute_exact_type_match(self.ctx.completion, &ty), | 80 | type_match: compute_type_match(self.ctx.completion, &ty), |
81 | ..CompletionRelevance::default() | 81 | ..CompletionRelevance::default() |
82 | }); | 82 | }); |
83 | 83 | ||
diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs index b1eba20e8..d681e2c91 100644 --- a/crates/ide_completion/src/render/function.rs +++ b/crates/ide_completion/src/render/function.rs | |||
@@ -8,7 +8,7 @@ use syntax::ast::Fn; | |||
8 | use crate::{ | 8 | use crate::{ |
9 | item::{CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, ImportEdit}, | 9 | item::{CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, ImportEdit}, |
10 | render::{ | 10 | render::{ |
11 | builder_ext::Params, compute_exact_name_match, compute_exact_type_match, compute_ref_match, | 11 | builder_ext::Params, compute_exact_name_match, compute_ref_match, compute_type_match, |
12 | RenderContext, | 12 | RenderContext, |
13 | }, | 13 | }, |
14 | }; | 14 | }; |
@@ -73,7 +73,7 @@ impl<'a> FunctionRender<'a> { | |||
73 | 73 | ||
74 | let ret_type = self.func.ret_type(self.ctx.db()); | 74 | let ret_type = self.func.ret_type(self.ctx.db()); |
75 | item.set_relevance(CompletionRelevance { | 75 | item.set_relevance(CompletionRelevance { |
76 | exact_type_match: compute_exact_type_match(self.ctx.completion, &ret_type), | 76 | type_match: compute_type_match(self.ctx.completion, &ret_type), |
77 | exact_name_match: compute_exact_name_match(self.ctx.completion, self.name.clone()), | 77 | exact_name_match: compute_exact_name_match(self.ctx.completion, self.name.clone()), |
78 | ..CompletionRelevance::default() | 78 | ..CompletionRelevance::default() |
79 | }); | 79 | }); |