Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-completion/src/render.rs')
| -rw-r--r-- | crates/ide-completion/src/render.rs | 407 |
1 files changed, 354 insertions, 53 deletions
diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs index fbbdffefe3..e48847c983 100644 --- a/crates/ide-completion/src/render.rs +++ b/crates/ide-completion/src/render.rs @@ -71,7 +71,7 @@ impl<'a, 'db> RenderContext<'a, 'db> { self.completion.config.snippet_cap } - fn db(&self) -> &'a RootDatabase { + fn db(&self) -> &'db RootDatabase { self.completion.db } @@ -181,9 +181,9 @@ pub(crate) fn render_field( if !expected_fn_type && let Some(receiver) = &dot_access.receiver - && let Some(receiver) = ctx.completion.sema.original_ast_node(receiver.clone()) + && let Some(receiver) = ctx.completion.sema.original_range_opt(receiver.syntax()) { - builder.insert(receiver.syntax().text_range().start(), "(".to_owned()); + builder.insert(receiver.range.start(), "(".to_owned()); builder.insert(ctx.source_range().end(), ")".to_owned()); let is_parens_needed = !matches!(dot_access.kind, DotAccessKind::Method); @@ -198,10 +198,10 @@ pub(crate) fn render_field( item.insert_text(field_with_receiver(receiver.as_deref(), &escaped_name)); } if let Some(receiver) = &dot_access.receiver - && let Some(original) = ctx.completion.sema.original_ast_node(receiver.clone()) + && let Some(original) = ctx.completion.sema.original_range_opt(receiver.syntax()) && let Some(ref_mode) = compute_ref_match(ctx.completion, ty) { - item.ref_match(ref_mode, original.syntax().text_range().start()); + item.ref_match(ref_mode, original.range.start()); } item.doc_aliases(ctx.doc_aliases); item.build(db) @@ -294,9 +294,9 @@ pub(crate) fn render_resolution_with_import_pat( Some(render_resolution_pat(ctx, pattern_ctx, local_name, Some(import_edit), resolution)) } -pub(crate) fn render_expr( - ctx: &CompletionContext<'_, '_>, - expr: &hir::term_search::Expr<'_>, +pub(crate) fn render_expr<'db>( + ctx: &CompletionContext<'_, 'db>, + expr: &hir::term_search::Expr<'db>, ) -> Option<Builder> { let mut i = 1; let mut snippet_formatter = |ty: &hir::Type<'_>| { @@ -341,7 +341,7 @@ pub(crate) fn render_expr( "Autogenerated expression by term search", ))); item.set_relevance(crate::CompletionRelevance { - type_match: compute_type_match(ctx, &expr.ty(ctx.db)), + type_match: compute_type_match(ctx, &ctx.rebase_ty(&expr.ty(ctx.db))), ..Default::default() }); for trait_ in expr.traits_used(ctx.db) { @@ -405,8 +405,8 @@ fn render_resolution_pat( } } -fn render_resolution_path( - ctx: RenderContext<'_, '_>, +fn render_resolution_path<'db>( + ctx: RenderContext<'_, 'db>, path_ctx: &PathCompletionCtx<'_>, local_name: hir::Name, import_to_add: Option<LocatedImport>, @@ -471,18 +471,21 @@ fn render_resolution_path( .insert_snippet(cap, ""); // set is snippet } } - let allow_module_path = matches!(path_ctx.kind, PathKind::Use) || !config.add_colons_to_module; + let allow_module_path = matches!(path_ctx.kind, PathKind::Use) + || completion.token.next_token().is_some_and(|it| it.kind() == syntax::T![::]) + || !config.add_colons_to_module; if !allow_module_path && matches!(resolution, ScopeDef::ModuleDef(Module(_))) { insert_text = format_smolstr!("{insert_text}::"); item.lookup_by(name.clone()).label(insert_text.clone()); } adds_ret_type_arrow(completion, path_ctx, &mut item, insert_text.into()); - let mut set_item_relevance = |ty: Type<'_>| { + let mut set_item_relevance = |ty: Type<'db>| { if !ty.is_unknown() { item.detail(ty.display(db, krate).to_string()); } + let ty = completion.rebase_ty(&ty); item.set_relevance(CompletionRelevance { type_match: compute_type_match(completion, &ty), exact_name_match: compute_exact_name_match(completion, &name), @@ -492,7 +495,13 @@ fn render_resolution_path( ..CompletionRelevance::default() }); - path_ref_match(completion, path_ctx, &ty, &mut item); + match resolution { + ScopeDef::Local(_) + | ScopeDef::ModuleDef(ModuleDef::Const(_) | ModuleDef::Static(_)) => { + path_ref_match(completion, path_ctx, &ty, &mut item) + } + _ => (), + } }; match resolution { @@ -680,8 +689,8 @@ fn compute_type_match( // &mut ty -> &ty if completion_ty.is_mutable_reference() - && let Some(expected_type) = expected_type.remove_ref() - && let Some(completion_ty) = completion_ty.remove_ref() + && let Some((expected_type, _)) = expected_type.as_reference() + && let Some((completion_ty, _)) = completion_ty.as_reference() { return match_types(ctx, &expected_type, &completion_ty); } @@ -709,18 +718,19 @@ fn compute_ref_match( ctx: &CompletionContext<'_, '_>, completion_ty: &hir::Type<'_>, ) -> Option<CompletionItemRefMode> { - let expected_type = ctx.expected_type.as_ref()?; - let expected_without_ref = expected_type.remove_ref(); - let completion_without_ref = completion_ty.remove_ref(); - if expected_type.could_unify_with(ctx.db, completion_ty) { + if compute_type_match(ctx, completion_ty).is_some() || completion_ty.is_unit() { return None; } - if let Some(expected_without_ref) = &expected_without_ref + let expected_type = ctx.expected_type.as_ref()?; + let expected_without_ref = expected_type.as_reference(); + let completion_without_ref = completion_ty.as_reference(); + + if let Some((expected_without_ref, _)) = &expected_without_ref && (completion_without_ref.is_none() || completion_ty.could_unify_with(ctx.db, expected_without_ref)) && completion_ty .autoderef(ctx.db) - .any(|ty| ty.could_unify_with(ctx.db, expected_without_ref)) + .any(|ty| !ty.is_unknown() && ty.could_unify_with(ctx.db, expected_without_ref)) { cov_mark::hit!(suggest_ref); let mutability = if expected_type.is_mutable_reference() { @@ -731,7 +741,7 @@ fn compute_ref_match( return Some(CompletionItemRefMode::Reference(mutability)); } - if let Some(completion_without_ref) = completion_without_ref + if let Some((completion_without_ref, _)) = completion_without_ref && completion_without_ref == *expected_type && completion_without_ref.is_copy(ctx.db) { @@ -750,10 +760,10 @@ fn path_ref_match( ) { if let Some(original_path) = &path_ctx.original_path { // At least one char was typed by the user already, in that case look for the original path - if let Some(original_path) = completion.sema.original_ast_node(original_path.clone()) + if let Some(original_path) = completion.sema.original_range_opt(original_path.syntax()) && let Some(ref_mode) = compute_ref_match(completion, ty) { - item.ref_match(ref_mode, original_path.syntax().text_range().start()); + item.ref_match(ref_mode, original_path.range.start()); } } else { // completion requested on an empty identifier, there is no path here yet. @@ -865,6 +875,7 @@ mod tests { exact_name_match, type_match, is_local, + is_missing, trait_, is_name_already_imported: _, requires_import, @@ -880,6 +891,7 @@ mod tests { (type_match == Some(CompletionRelevanceTypeMatch::CouldUnify), "type_could_unify"), (exact_name_match, "name"), (is_local, "local"), + (is_missing, "missing"), (postfix_match == Some(CompletionRelevancePostfixMatch::Exact), "snippet"), (trait_.is_some_and(|it| it.is_op_method), "op_method"), (requires_import, "requires_import"), @@ -944,9 +956,9 @@ fn main() { } "#, expect![[r#" - st dep::test_mod_b::Struct {…} dep::test_mod_b::Struct { } [type_could_unify] - ex dep::test_mod_b::Struct { } [type_could_unify] - st Struct Struct [type_could_unify+requires_import] + st dep::test_mod_b::Struct {…} dep::test_mod_b::Struct { } [type] + ex dep::test_mod_b::Struct { } [type] + st Struct Struct [type+requires_import] md dep:: [] fn main() fn() [] fn test(…) fn(Struct) [] @@ -984,7 +996,7 @@ fn main() { } "#, expect![[r#" - un Union Union [type_could_unify+requires_import] + un Union Union [type+requires_import] md dep:: [] fn main() fn() [] fn test(…) fn(Union) [] @@ -1020,9 +1032,9 @@ fn main() { } "#, expect![[r#" - ev dep::test_mod_b::Enum::variant dep::test_mod_b::Enum::variant [type_could_unify] - ex dep::test_mod_b::Enum::variant [type_could_unify] - en Enum Enum [type_could_unify+requires_import] + ev dep::test_mod_b::Enum::variant dep::test_mod_b::Enum::variant [type] + ex dep::test_mod_b::Enum::variant [type] + en Enum Enum [type+requires_import] md dep:: [] fn main() fn() [] fn test(…) fn(Enum) [] @@ -1058,11 +1070,13 @@ fn main() { } "#, expect![[r#" - ev dep::test_mod_b::Enum::Variant dep::test_mod_b::Enum::Variant [type_could_unify] - ex dep::test_mod_b::Enum::Variant [type_could_unify] + ev dep::test_mod_b::Enum::Variant dep::test_mod_b::Enum::Variant [type] + ex dep::test_mod_b::Enum::Variant [type] + ev Variant Variant [type+requires_import] md dep:: [] fn main() fn() [] fn test(…) fn(Enum) [] + ev Variant Variant [requires_import] "#]], ); } @@ -1122,7 +1136,7 @@ fn main() { } "#, expect![[r#" - ct CONST i32 [type_could_unify+requires_import] + ct CONST i32 [type+requires_import] md dep:: [] fn main() fn() [] fn test(…) fn(i32) [] @@ -1154,7 +1168,7 @@ fn main() { } "#, expect![[r#" - sc STATIC i32 [type_could_unify+requires_import] + sc STATIC i32 [type+requires_import] md dep:: [] fn main() fn() [] fn test(…) fn(i32) [] @@ -1281,6 +1295,7 @@ fn main() { Foo::Fo$0 } exact_name_match: false, type_match: None, is_local: false, + is_missing: false, trait_: None, is_name_already_imported: false, requires_import: false, @@ -1333,6 +1348,7 @@ fn main() { Foo::Fo$0 } exact_name_match: false, type_match: None, is_local: false, + is_missing: false, trait_: None, is_name_already_imported: false, requires_import: false, @@ -1478,6 +1494,7 @@ fn main() { Foo::Fo$0 } exact_name_match: false, type_match: None, is_local: false, + is_missing: false, trait_: None, is_name_already_imported: false, requires_import: false, @@ -1564,6 +1581,7 @@ fn main() { let _: m::Spam = S$0 } Exact, ), is_local: false, + is_missing: false, trait_: None, is_name_already_imported: false, requires_import: false, @@ -1602,6 +1620,7 @@ fn main() { let _: m::Spam = S$0 } Exact, ), is_local: false, + is_missing: false, trait_: None, is_name_already_imported: false, requires_import: false, @@ -1653,6 +1672,7 @@ fn main() { som$0 } exact_name_match: false, type_match: None, is_local: false, + is_missing: false, trait_: None, is_name_already_imported: false, requires_import: false, @@ -1712,6 +1732,7 @@ fn main() { som$0 } exact_name_match: false, type_match: None, is_local: false, + is_missing: false, trait_: None, is_name_already_imported: false, requires_import: false, @@ -1755,6 +1776,7 @@ fn main() { A$0 } exact_name_match: false, type_match: None, is_local: false, + is_missing: false, trait_: None, is_name_already_imported: false, requires_import: false, @@ -1798,6 +1820,7 @@ fn main() { A$0 } exact_name_match: false, type_match: None, is_local: false, + is_missing: false, trait_: None, is_name_already_imported: false, requires_import: false, @@ -1843,6 +1866,7 @@ fn main() { A::$0 } exact_name_match: false, type_match: None, is_local: false, + is_missing: false, trait_: None, is_name_already_imported: false, requires_import: false, @@ -1879,6 +1903,7 @@ fn main() { A::$0 } exact_name_match: false, type_match: None, is_local: false, + is_missing: false, trait_: None, is_name_already_imported: false, requires_import: false, @@ -1929,6 +1954,7 @@ fn main() { A$0 } exact_name_match: false, type_match: None, is_local: false, + is_missing: false, trait_: None, is_name_already_imported: false, requires_import: false, @@ -1972,6 +1998,7 @@ fn main() { A$0 } exact_name_match: false, type_match: None, is_local: false, + is_missing: false, trait_: None, is_name_already_imported: false, requires_import: false, @@ -2012,6 +2039,7 @@ impl A$0 exact_name_match: false, type_match: None, is_local: false, + is_missing: false, trait_: None, is_name_already_imported: false, requires_import: false, @@ -2052,6 +2080,7 @@ fn main() { A$0 } exact_name_match: false, type_match: None, is_local: false, + is_missing: false, trait_: None, is_name_already_imported: false, requires_import: false, @@ -2096,6 +2125,7 @@ fn main() { a$0 } exact_name_match: false, type_match: None, is_local: false, + is_missing: false, trait_: None, is_name_already_imported: false, requires_import: false, @@ -2140,6 +2170,7 @@ fn main() { A { the$0 } } CouldUnify, ), is_local: false, + is_missing: false, trait_: None, is_name_already_imported: false, requires_import: false, @@ -2195,6 +2226,7 @@ impl S { exact_name_match: false, type_match: None, is_local: false, + is_missing: false, trait_: None, is_name_already_imported: false, requires_import: false, @@ -2288,6 +2320,7 @@ use self::E::*; exact_name_match: false, type_match: None, is_local: false, + is_missing: false, trait_: None, is_name_already_imported: false, requires_import: false, @@ -2360,6 +2393,7 @@ fn foo(s: S) { s.$0 } exact_name_match: false, type_match: None, is_local: false, + is_missing: false, trait_: None, is_name_already_imported: false, requires_import: false, @@ -2580,6 +2614,7 @@ fn f() -> i32 { Exact, ), is_local: false, + is_missing: false, trait_: None, is_name_already_imported: false, requires_import: false, @@ -2639,7 +2674,6 @@ fn go(world: &WorldSnapshot) { go(w$0) } st WorldSnapshot {…} WorldSnapshot { _f: () } [] st &WorldSnapshot {…} [type] st WorldSnapshot WorldSnapshot [] - st &WorldSnapshot [type] fn go(…) fn(&WorldSnapshot) [] "#]], ); @@ -2687,6 +2721,7 @@ fn main() { exact_name_match: false, type_match: None, is_local: true, + is_missing: false, trait_: None, is_name_already_imported: false, requires_import: false, @@ -2705,6 +2740,204 @@ fn main() { } #[test] + fn complete_ref_match_in_macro() { + check_kinds( + r#" +macro_rules! id { ($($t:tt)*) => ($($t)*); } +fn foo(data: &i32) {} +fn main() { + let indent = 2i32; + id!(foo(i$0)) +} +"#, + &[CompletionItemKind::SymbolKind(SymbolKind::Local)], + expect![[r#" + [ + CompletionItem { + label: "indent", + detail_left: None, + detail_right: Some( + "i32", + ), + source_range: 114..115, + delete: 114..115, + insert: "indent", + kind: SymbolKind( + Local, + ), + detail: "i32", + relevance: CompletionRelevance { + exact_name_match: false, + type_match: None, + is_local: true, + is_missing: false, + trait_: None, + is_name_already_imported: false, + requires_import: false, + is_private_editable: false, + postfix_match: None, + function: None, + is_skipping_completion: false, + has_local_inherent_impl: false, + is_deprecated: false, + }, + ref_match: "&@114", + }, + ] + "#]], + ); + + check_kinds( + r#" +macro_rules! id { ($($t:tt)*) => ($($t)*); } +fn foo(data: &i32) {} +fn indent() -> i32 { i32 } +fn main() { + id!(foo(i$0)) +} +"#, + &[CompletionItemKind::SymbolKind(SymbolKind::Function)], + expect![[r#" + [ + CompletionItem { + label: "foo(…)", + detail_left: None, + detail_right: Some( + "fn(&i32)", + ), + source_range: 118..119, + delete: 118..119, + insert: "foo(${1:data})$0", + kind: SymbolKind( + Function, + ), + lookup: "foo", + detail: "fn(&i32)", + trigger_call_info: true, + }, + CompletionItem { + label: "indent()", + detail_left: None, + detail_right: Some( + "fn() -> i32", + ), + source_range: 118..119, + delete: 118..119, + insert: "indent()$0", + kind: SymbolKind( + Function, + ), + lookup: "indent", + detail: "fn() -> i32", + ref_match: "&@118", + }, + CompletionItem { + label: "main()", + detail_left: None, + detail_right: Some( + "fn()", + ), + source_range: 118..119, + delete: 118..119, + insert: "main()$0", + kind: SymbolKind( + Function, + ), + lookup: "main", + detail: "fn()", + }, + ] + "#]], + ); + + // FIXME: It is best to test `S.in` if speculative execution is implemented + check_kinds( + r#" +macro_rules! id { ($($t:tt)*) => ($($t)*); } +fn foo(data: &i32) {} +struct S; +impl S {fn indent(&self) -> i32 { i32 }} +fn main() { + id!(foo(S.i$0)) +} +"#, + &[CompletionItemKind::SymbolKind(SymbolKind::Method)], + expect![[r#" + [ + CompletionItem { + label: "indent()", + detail_left: None, + detail_right: Some( + "fn(&self) -> i32", + ), + source_range: 144..145, + delete: 144..145, + insert: "indent()$0", + kind: SymbolKind( + Method, + ), + lookup: "indent", + detail: "fn(&self) -> i32", + relevance: CompletionRelevance { + exact_name_match: false, + type_match: None, + is_local: false, + is_missing: false, + trait_: None, + is_name_already_imported: false, + requires_import: false, + is_private_editable: false, + postfix_match: None, + function: Some( + CompletionRelevanceFn { + has_params: true, + has_self_param: true, + return_type: Other, + }, + ), + is_skipping_completion: false, + has_local_inherent_impl: false, + is_deprecated: false, + }, + ref_match: "&@142", + }, + ] + "#]], + ); + + check_kinds( + r#" +macro_rules! id { ($($t:tt)*) => ($($t)*); } +fn foo(data: &i32) {} +struct S { indent: i32 } +fn main(s: S) { + id!(foo(s.i$0)) +} +"#, + &[CompletionItemKind::SymbolKind(SymbolKind::Field)], + expect![[r#" + [ + CompletionItem { + label: "indent", + detail_left: None, + detail_right: Some( + "i32", + ), + source_range: 122..123, + delete: 122..123, + insert: "indent", + kind: SymbolKind( + Field, + ), + detail: "i32", + ref_match: "&@120", + }, + ] + "#]], + ); + } + + #[test] fn too_many_arguments() { cov_mark::check!(too_many_arguments); check_relevance( @@ -2825,6 +3058,37 @@ mod b { } #[test] + fn score_patterns() { + check_relevance( + r#" +struct Foo(Bar); +struct Bar { field: i32 } +fn go(Foo($0): Foo) {} +"#, + expect![[r#" + bn Bar {…} Bar { field$1 }$0 [type] + st Bar [] + st Foo [] + bn Foo(…) Foo($1)$0 [] + "#]], + ); + + check_relevance( + r#" +struct Foo(Bar); +enum Bar { Variant { field: i32 } } +fn go(foo: Foo) { match foo { Foo($0) } } +"#, + expect![[r#" + bn Bar::Variant {…} Bar::Variant { field$1 }$0 [type] + en Bar [] + st Foo [] + bn Foo(…) Foo($1)$0 [] + "#]], + ); + } + + #[test] fn test_avoid_redundant_suggestion() { check_relevance( r#" @@ -2865,7 +3129,6 @@ fn main() { st S S [] st &mut S [type] st S S [] - st &mut S [type] fn foo(…) fn(&mut S) [] fn main() fn() [] "#]], @@ -2879,6 +3142,7 @@ fn main() { foo(&mut $0); } "#, + // FIXME: There are many `S` here expect![[r#" lc s S [type+name+local] st S S [type] @@ -2940,12 +3204,51 @@ fn main() { st &mut S(…) [type] lc ssss S<u32> [local] lc &mut ssss [type+local] - st S S<{unknown}> [] - st &mut S [type] + st S S<T> [] fn foo(…) fn(&mut S<T>) [] fn main() fn() [] "#]], ); + // Regression test https://github.com/rust-lang/rust-analyzer/issues/22324 + check_relevance( + r#" +//- minicore: deref +struct S<T>(T); +impl<T> core::ops::Deref for S<T> { + type Target = T; +} +fn foo<T>(s: &u32) {} +fn main() { + let ssss = S(); + foo($0); +} + "#, + // FIXME: term_search exclude ssss.0 (field.ty().is_unknown()) + expect![[r#" + ex ssss.0 [type_could_unify] + lc ssss S<{unknown}> [local] + st S S<T> [] + md core:: [] + fn foo(…) fn(&u32) [] + fn main() fn() [] + "#]], + ); + check_relevance( + r#" +//- minicore: deref +fn foo<T>(s: &T) {} +fn main() { + let ssss = &mut 2i32; + foo($0); +} + "#, + expect![[r#" + lc ssss &mut i32 [type_could_unify+local] + md core:: [] + fn foo(…) fn(&T) [] + fn main() fn() [] + "#]], + ); } #[test] @@ -3016,9 +3319,7 @@ fn main() { lc t T [local] lc &t [type+local] st S S [] - st &S [type] st T T [] - st &T [type] md core:: [] fn foo(…) fn(&S) [] fn main() fn() [] @@ -3065,9 +3366,7 @@ fn main() { lc t T [local] lc &mut t [type+local] st S S [] - st &mut S [type] st T T [] - st &mut T [type] md core:: [] fn foo(…) fn(&mut S) [] fn main() fn() [] @@ -3131,7 +3430,6 @@ fn bar(t: &Foo) {} ev Foo::B Foo::B [] ev &Foo::B [type] en Foo Foo [] - en &Foo [type] fn bar(…) fn(&Foo) [] fn foo() fn() [] "#]], @@ -3166,9 +3464,7 @@ fn main() { st &S [type] ex core::ops::Deref::deref(&bar()) [type_could_unify] st S S [] - st &S [type] st T T [] - st &T [type] fn bar() fn() -> T [] fn &bar() [type] md core:: [] @@ -3499,6 +3795,7 @@ fn foo(f: Foo) { let _: &u32 = f.b$0 } exact_name_match: false, type_match: None, is_local: false, + is_missing: false, trait_: None, is_name_already_imported: false, requires_import: false, @@ -3594,6 +3891,7 @@ fn foo() { Exact, ), is_local: false, + is_missing: false, trait_: None, is_name_already_imported: false, requires_import: false, @@ -3648,6 +3946,7 @@ fn main() { exact_name_match: false, type_match: None, is_local: false, + is_missing: false, trait_: None, is_name_already_imported: false, requires_import: false, @@ -3690,14 +3989,14 @@ fn foo() { } "#, expect![[r#" - ev Foo::B Foo::B [type_could_unify] - ev Foo::A(…) Foo::A(T) [type_could_unify] lc foo Foo<u32> [type+local] ex Foo::B [type] ex foo [type] - en Foo Foo<{unknown}> [type_could_unify] + ev Foo::B Foo::B [type_could_unify] + ev Foo::A(…) Foo::A(T) [type_could_unify] + en Foo Foo<T> [type_could_unify] + fn baz() fn() -> Foo<T> [type_could_unify] fn bar() fn() -> Foo<u8> [] - fn baz() fn() -> Foo<T> [] fn foo() fn() [] "#]], ); @@ -3727,6 +4026,7 @@ fn main() { &[CompletionItemKind::Snippet, CompletionItemKind::SymbolKind(SymbolKind::Method)], expect![[r#" sn not !expr [snippet] + me not() fn(self) -> <Self as Not>::Output [type_could_unify+requires_import] sn box Box::new(expr) [] sn call function(expr) [] sn const const {} [] @@ -3740,7 +4040,6 @@ fn main() { sn return return expr [] sn unsafe unsafe {} [] sn while while expr {} [] - me not() fn(self) -> <Self as Not>::Output [requires_import] "#]], ); } @@ -3791,7 +4090,7 @@ enum Foo { en Foo Foo [] st Other Other [] sp Self Foo [] - st Vec<…> Vec<{unknown}> [] + st Vec<…> Vec<T> [] "#]], ); } @@ -4140,6 +4439,7 @@ fn main() { exact_name_match: false, type_match: None, is_local: false, + is_missing: false, trait_: Some( CompletionRelevanceTraitInfo { notable_trait: true, @@ -4176,6 +4476,7 @@ fn main() { exact_name_match: false, type_match: None, is_local: false, + is_missing: false, trait_: Some( CompletionRelevanceTraitInfo { notable_trait: true, |