]> git.lizzy.rs Git - rust.git/blob - crates/ide_completion/src/completions/trait_impl.rs
Merge #10623
[rust.git] / crates / ide_completion / src / completions / trait_impl.rs
1 //! Completion for associated items in a trait implementation.
2 //!
3 //! This module adds the completion items related to implementing associated
4 //! items within an `impl Trait for Struct` block. The current context node
5 //! must be within either a `FN`, `TYPE_ALIAS`, or `CONST` node
6 //! and an direct child of an `IMPL`.
7 //!
8 //! # Examples
9 //!
10 //! Considering the following trait `impl`:
11 //!
12 //! ```ignore
13 //! trait SomeTrait {
14 //!     fn foo();
15 //! }
16 //!
17 //! impl SomeTrait for () {
18 //!     fn f$0
19 //! }
20 //! ```
21 //!
22 //! may result in the completion of the following method:
23 //!
24 //! ```ignore
25 //! # trait SomeTrait {
26 //! #    fn foo();
27 //! # }
28 //!
29 //! impl SomeTrait for () {
30 //!     fn foo() {}$0
31 //! }
32 //! ```
33
34 use hir::{self, HasAttrs, HasSource};
35 use ide_db::{path_transform::PathTransform, traits::get_missing_assoc_items, SymbolKind};
36 use syntax::{
37     ast::{self, edit_in_place::AttrsOwnerEdit},
38     display::function_declaration,
39     AstNode, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, T,
40 };
41 use text_edit::TextEdit;
42
43 use crate::{CompletionContext, CompletionItem, CompletionItemKind, Completions};
44
45 #[derive(Debug, PartialEq, Eq)]
46 enum ImplCompletionKind {
47     All,
48     Fn,
49     TypeAlias,
50     Const,
51 }
52
53 pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) {
54     if let Some((kind, trigger, impl_def)) = completion_match(ctx.token.clone()) {
55         if let Some(hir_impl) = ctx.sema.to_def(&impl_def) {
56             get_missing_assoc_items(&ctx.sema, &impl_def).into_iter().for_each(|item| match item {
57                 hir::AssocItem::Function(fn_item)
58                     if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Fn =>
59                 {
60                     add_function_impl(&trigger, acc, ctx, fn_item, hir_impl)
61                 }
62                 hir::AssocItem::TypeAlias(type_item)
63                     if kind == ImplCompletionKind::All || kind == ImplCompletionKind::TypeAlias =>
64                 {
65                     add_type_alias_impl(&trigger, acc, ctx, type_item)
66                 }
67                 hir::AssocItem::Const(const_item)
68                     if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Const =>
69                 {
70                     add_const_impl(&trigger, acc, ctx, const_item, hir_impl)
71                 }
72                 _ => {}
73             });
74         }
75     }
76 }
77
78 fn completion_match(mut token: SyntaxToken) -> Option<(ImplCompletionKind, SyntaxNode, ast::Impl)> {
79     // For keyword without name like `impl .. { fn $0 }`, the current position is inside
80     // the whitespace token, which is outside `FN` syntax node.
81     // We need to follow the previous token in this case.
82     if token.kind() == SyntaxKind::WHITESPACE {
83         token = token.prev_token()?;
84     }
85
86     let parent_kind = token.parent().map_or(SyntaxKind::EOF, |it| it.kind());
87     let impl_item_offset = match token.kind() {
88         // `impl .. { const $0 }`
89         // ERROR      0
90         //   CONST_KW <- *
91         T![const] => 0,
92         // `impl .. { fn/type $0 }`
93         // FN/TYPE_ALIAS  0
94         //   FN_KW        <- *
95         T![fn] | T![type] => 0,
96         // `impl .. { fn/type/const foo$0 }`
97         // FN/TYPE_ALIAS/CONST  1
98         //  NAME                0
99         //    IDENT             <- *
100         SyntaxKind::IDENT if parent_kind == SyntaxKind::NAME => 1,
101         // `impl .. { foo$0 }`
102         // MACRO_CALL       3
103         //  PATH            2
104         //    PATH_SEGMENT  1
105         //      NAME_REF    0
106         //        IDENT     <- *
107         SyntaxKind::IDENT if parent_kind == SyntaxKind::NAME_REF => 3,
108         _ => return None,
109     };
110
111     let impl_item = token.ancestors().nth(impl_item_offset)?;
112     // Must directly belong to an impl block.
113     // IMPL
114     //   ASSOC_ITEM_LIST
115     //     <item>
116     let impl_def = ast::Impl::cast(impl_item.parent()?.parent()?)?;
117     let kind = match impl_item.kind() {
118         // `impl ... { const $0 fn/type/const }`
119         _ if token.kind() == T![const] => ImplCompletionKind::Const,
120         SyntaxKind::CONST | SyntaxKind::ERROR => ImplCompletionKind::Const,
121         SyntaxKind::TYPE_ALIAS => ImplCompletionKind::TypeAlias,
122         SyntaxKind::FN => ImplCompletionKind::Fn,
123         SyntaxKind::MACRO_CALL => ImplCompletionKind::All,
124         _ => return None,
125     };
126     Some((kind, impl_item, impl_def))
127 }
128
129 fn add_function_impl(
130     fn_def_node: &SyntaxNode,
131     acc: &mut Completions,
132     ctx: &CompletionContext,
133     func: hir::Function,
134     impl_def: hir::Impl,
135 ) {
136     let fn_name = func.name(ctx.db).to_string();
137
138     let label = if func.assoc_fn_params(ctx.db).is_empty() {
139         format!("fn {}()", fn_name)
140     } else {
141         format!("fn {}(..)", fn_name)
142     };
143
144     let completion_kind = if func.self_param(ctx.db).is_some() {
145         CompletionItemKind::Method
146     } else {
147         CompletionItemKind::SymbolKind(SymbolKind::Function)
148     };
149     let mut item = CompletionItem::new(completion_kind, ctx.source_range(), label);
150     item.lookup_by(fn_name).set_documentation(func.docs(ctx.db));
151
152     let range = replacement_range(ctx, fn_def_node);
153
154     if let Some(source) = func.source(ctx.db) {
155         let assoc_item = ast::AssocItem::Fn(source.value);
156         if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) {
157             let transformed_fn = match transformed_item {
158                 ast::AssocItem::Fn(func) => func,
159                 _ => unreachable!(),
160             };
161
162             let function_decl = function_declaration(&transformed_fn);
163             match ctx.config.snippet_cap {
164                 Some(cap) => {
165                     let snippet = format!("{} {{\n    $0\n}}", function_decl);
166                     item.snippet_edit(cap, TextEdit::replace(range, snippet));
167                 }
168                 None => {
169                     let header = format!("{} {{", function_decl);
170                     item.text_edit(TextEdit::replace(range, header));
171                 }
172             };
173             item.add_to(acc);
174         }
175     }
176 }
177
178 /// Transform a relevant associated item to inline generics from the impl, remove attrs and docs, etc.
179 fn get_transformed_assoc_item(
180     ctx: &CompletionContext,
181     assoc_item: ast::AssocItem,
182     impl_def: hir::Impl,
183 ) -> Option<ast::AssocItem> {
184     let assoc_item = assoc_item.clone_for_update();
185     let trait_ = impl_def.trait_(ctx.db)?;
186     let source_scope = &ctx.sema.scope_for_def(trait_);
187     let target_scope = &ctx.sema.scope(ctx.sema.source(impl_def)?.syntax().value);
188     let transform = PathTransform::trait_impl(
189         target_scope,
190         source_scope,
191         trait_,
192         impl_def.source(ctx.db)?.value,
193     );
194
195     transform.apply(assoc_item.syntax());
196     if let ast::AssocItem::Fn(func) = &assoc_item {
197         func.remove_attrs_and_docs()
198     }
199     Some(assoc_item)
200 }
201
202 fn add_type_alias_impl(
203     type_def_node: &SyntaxNode,
204     acc: &mut Completions,
205     ctx: &CompletionContext,
206     type_alias: hir::TypeAlias,
207 ) {
208     let alias_name = type_alias.name(ctx.db).to_string();
209
210     let snippet = format!("type {} = ", alias_name);
211
212     let range = replacement_range(ctx, type_def_node);
213     let mut item = CompletionItem::new(SymbolKind::TypeAlias, ctx.source_range(), snippet.clone());
214     item.text_edit(TextEdit::replace(range, snippet))
215         .lookup_by(alias_name)
216         .set_documentation(type_alias.docs(ctx.db));
217     item.add_to(acc);
218 }
219
220 fn add_const_impl(
221     const_def_node: &SyntaxNode,
222     acc: &mut Completions,
223     ctx: &CompletionContext,
224     const_: hir::Const,
225     impl_def: hir::Impl,
226 ) {
227     let const_name = const_.name(ctx.db).map(|n| n.to_string());
228
229     if let Some(const_name) = const_name {
230         if let Some(source) = const_.source(ctx.db) {
231             let assoc_item = ast::AssocItem::Const(source.value);
232             if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) {
233                 let transformed_const = match transformed_item {
234                     ast::AssocItem::Const(const_) => const_,
235                     _ => unreachable!(),
236                 };
237
238                 let snippet = make_const_compl_syntax(&transformed_const);
239
240                 let range = replacement_range(ctx, const_def_node);
241                 let mut item =
242                     CompletionItem::new(SymbolKind::Const, ctx.source_range(), snippet.clone());
243                 item.text_edit(TextEdit::replace(range, snippet))
244                     .lookup_by(const_name)
245                     .set_documentation(const_.docs(ctx.db));
246                 item.add_to(acc);
247             }
248         }
249     }
250 }
251
252 fn make_const_compl_syntax(const_: &ast::Const) -> String {
253     const_.remove_attrs_and_docs();
254
255     let const_start = const_.syntax().text_range().start();
256     let const_end = const_.syntax().text_range().end();
257
258     let start =
259         const_.syntax().first_child_or_token().map_or(const_start, |f| f.text_range().start());
260
261     let end = const_
262         .syntax()
263         .children_with_tokens()
264         .find(|s| s.kind() == T![;] || s.kind() == T![=])
265         .map_or(const_end, |f| f.text_range().start());
266
267     let len = end - start;
268     let range = TextRange::new(0.into(), len);
269
270     let syntax = const_.syntax().text().slice(range).to_string();
271
272     format!("{} = ", syntax.trim_end())
273 }
274
275 fn replacement_range(ctx: &CompletionContext, item: &SyntaxNode) -> TextRange {
276     let first_child = item
277         .children_with_tokens()
278         .find(|child| {
279             !matches!(child.kind(), SyntaxKind::COMMENT | SyntaxKind::WHITESPACE | SyntaxKind::ATTR)
280         })
281         .unwrap_or_else(|| SyntaxElement::Node(item.clone()));
282
283     TextRange::new(first_child.text_range().start(), ctx.source_range().end())
284 }
285
286 #[cfg(test)]
287 mod tests {
288     use expect_test::{expect, Expect};
289
290     use crate::tests::{check_edit, completion_list_no_kw};
291
292     fn check(ra_fixture: &str, expect: Expect) {
293         let actual = completion_list_no_kw(ra_fixture);
294         expect.assert_eq(&actual)
295     }
296
297     #[test]
298     fn no_completion_inside_fn() {
299         check(
300             r"
301 trait Test { fn test(); fn test2(); }
302 struct T;
303
304 impl Test for T {
305     fn test() {
306         t$0
307     }
308 }
309 ",
310             expect![[r#"
311                 sp Self
312                 tt Test
313                 st T
314                 bt u32
315             "#]],
316         );
317
318         check(
319             r"
320 trait Test { fn test(); fn test2(); }
321 struct T;
322
323 impl Test for T {
324     fn test() {
325         fn t$0
326     }
327 }
328 ",
329             expect![[""]],
330         );
331
332         check(
333             r"
334 trait Test { fn test(); fn test2(); }
335 struct T;
336
337 impl Test for T {
338     fn test() {
339         fn $0
340     }
341 }
342 ",
343             expect![[""]],
344         );
345
346         // https://github.com/rust-analyzer/rust-analyzer/pull/5976#issuecomment-692332191
347         check(
348             r"
349 trait Test { fn test(); fn test2(); }
350 struct T;
351
352 impl Test for T {
353     fn test() {
354         foo.$0
355     }
356 }
357 ",
358             expect![[r#""#]],
359         );
360
361         check(
362             r"
363 trait Test { fn test(_: i32); fn test2(); }
364 struct T;
365
366 impl Test for T {
367     fn test(t$0)
368 }
369 ",
370             expect![[r#"
371                 sp Self
372                 st T
373             "#]],
374         );
375
376         check(
377             r"
378 trait Test { fn test(_: fn()); fn test2(); }
379 struct T;
380
381 impl Test for T {
382     fn test(f: fn $0)
383 }
384 ",
385             expect![[r#"
386                 sp Self
387                 st T
388             "#]],
389         );
390     }
391
392     #[test]
393     fn no_completion_inside_const() {
394         check(
395             r"
396 trait Test { const TEST: fn(); const TEST2: u32; type Test; fn test(); }
397 struct T;
398
399 impl Test for T {
400     const TEST: fn $0
401 }
402 ",
403             expect![[r#""#]],
404         );
405
406         check(
407             r"
408 trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
409 struct T;
410
411 impl Test for T {
412     const TEST: T$0
413 }
414 ",
415             expect![[r#"
416                 sp Self
417                 tt Test
418                 st T
419                 bt u32
420             "#]],
421         );
422
423         check(
424             r"
425 trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
426 struct T;
427
428 impl Test for T {
429     const TEST: u32 = f$0
430 }
431 ",
432             expect![[r#"
433                 sp Self
434                 tt Test
435                 st T
436                 bt u32
437             "#]],
438         );
439
440         check(
441             r"
442 trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
443 struct T;
444
445 impl Test for T {
446     const TEST: u32 = {
447         t$0
448     };
449 }
450 ",
451             expect![[r#"
452                 sp Self
453                 tt Test
454                 st T
455                 bt u32
456             "#]],
457         );
458
459         check(
460             r"
461 trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
462 struct T;
463
464 impl Test for T {
465     const TEST: u32 = {
466         fn $0
467     };
468 }
469 ",
470             expect![[""]],
471         );
472
473         check(
474             r"
475 trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); }
476 struct T;
477
478 impl Test for T {
479     const TEST: u32 = {
480         fn t$0
481     };
482 }
483 ",
484             expect![[""]],
485         );
486     }
487
488     #[test]
489     fn no_completion_inside_type() {
490         check(
491             r"
492 trait Test { type Test; type Test2; fn test(); }
493 struct T;
494
495 impl Test for T {
496     type Test = T$0;
497 }
498 ",
499             expect![[r#"
500                 sp Self
501                 tt Test
502                 st T
503                 bt u32
504             "#]],
505         );
506
507         check(
508             r"
509 trait Test { type Test; type Test2; fn test(); }
510 struct T;
511
512 impl Test for T {
513     type Test = fn $0;
514 }
515 ",
516             expect![[r#"
517                 sp Self
518                 tt Test
519                 st T
520                 bt u32
521             "#]],
522         );
523     }
524
525     #[test]
526     fn name_ref_single_function() {
527         check_edit(
528             "test",
529             r#"
530 trait Test {
531     fn test();
532 }
533 struct T;
534
535 impl Test for T {
536     t$0
537 }
538 "#,
539             r#"
540 trait Test {
541     fn test();
542 }
543 struct T;
544
545 impl Test for T {
546     fn test() {
547     $0
548 }
549 }
550 "#,
551         );
552     }
553
554     #[test]
555     fn single_function() {
556         check_edit(
557             "test",
558             r#"
559 trait Test {
560     fn test();
561 }
562 struct T;
563
564 impl Test for T {
565     fn t$0
566 }
567 "#,
568             r#"
569 trait Test {
570     fn test();
571 }
572 struct T;
573
574 impl Test for T {
575     fn test() {
576     $0
577 }
578 }
579 "#,
580         );
581     }
582
583     #[test]
584     fn generic_fn() {
585         check_edit(
586             "foo",
587             r#"
588 trait Test {
589     fn foo<T>();
590 }
591 struct T;
592
593 impl Test for T {
594     fn f$0
595 }
596 "#,
597             r#"
598 trait Test {
599     fn foo<T>();
600 }
601 struct T;
602
603 impl Test for T {
604     fn foo<T>() {
605     $0
606 }
607 }
608 "#,
609         );
610         check_edit(
611             "foo",
612             r#"
613 trait Test {
614     fn foo<T>() where T: Into<String>;
615 }
616 struct T;
617
618 impl Test for T {
619     fn f$0
620 }
621 "#,
622             r#"
623 trait Test {
624     fn foo<T>() where T: Into<String>;
625 }
626 struct T;
627
628 impl Test for T {
629     fn foo<T>()
630 where T: Into<String> {
631     $0
632 }
633 }
634 "#,
635         );
636     }
637
638     #[test]
639     fn associated_type() {
640         check_edit(
641             "SomeType",
642             r#"
643 trait Test {
644     type SomeType;
645 }
646
647 impl Test for () {
648     type S$0
649 }
650 "#,
651             "
652 trait Test {
653     type SomeType;
654 }
655
656 impl Test for () {
657     type SomeType = \n\
658 }
659 ",
660         );
661     }
662
663     #[test]
664     fn associated_const() {
665         check_edit(
666             "SOME_CONST",
667             r#"
668 trait Test {
669     const SOME_CONST: u16;
670 }
671
672 impl Test for () {
673     const S$0
674 }
675 "#,
676             "
677 trait Test {
678     const SOME_CONST: u16;
679 }
680
681 impl Test for () {
682     const SOME_CONST: u16 = \n\
683 }
684 ",
685         );
686
687         check_edit(
688             "SOME_CONST",
689             r#"
690 trait Test {
691     const SOME_CONST: u16 = 92;
692 }
693
694 impl Test for () {
695     const S$0
696 }
697 "#,
698             "
699 trait Test {
700     const SOME_CONST: u16 = 92;
701 }
702
703 impl Test for () {
704     const SOME_CONST: u16 = \n\
705 }
706 ",
707         );
708     }
709
710     #[test]
711     fn complete_without_name() {
712         let test = |completion: &str, hint: &str, completed: &str, next_sibling: &str| {
713             check_edit(
714                 completion,
715                 &format!(
716                     r#"
717 trait Test {{
718     type Foo;
719     const CONST: u16;
720     fn bar();
721 }}
722 struct T;
723
724 impl Test for T {{
725     {}
726     {}
727 }}
728 "#,
729                     hint, next_sibling
730                 ),
731                 &format!(
732                     r#"
733 trait Test {{
734     type Foo;
735     const CONST: u16;
736     fn bar();
737 }}
738 struct T;
739
740 impl Test for T {{
741     {}
742     {}
743 }}
744 "#,
745                     completed, next_sibling
746                 ),
747             )
748         };
749
750         // Enumerate some possible next siblings.
751         for next_sibling in &[
752             "",
753             "fn other_fn() {}", // `const $0 fn` -> `const fn`
754             "type OtherType = i32;",
755             "const OTHER_CONST: i32 = 0;",
756             "async fn other_fn() {}",
757             "unsafe fn other_fn() {}",
758             "default fn other_fn() {}",
759             "default type OtherType = i32;",
760             "default const OTHER_CONST: i32 = 0;",
761         ] {
762             test("bar", "fn $0", "fn bar() {\n    $0\n}", next_sibling);
763             test("Foo", "type $0", "type Foo = ", next_sibling);
764             test("CONST", "const $0", "const CONST: u16 = ", next_sibling);
765         }
766     }
767
768     #[test]
769     fn snippet_does_not_overwrite_comment_or_attr() {
770         let test = |completion: &str, hint: &str, completed: &str| {
771             check_edit(
772                 completion,
773                 &format!(
774                     r#"
775 trait Foo {{
776     type Type;
777     fn function();
778     const CONST: i32 = 0;
779 }}
780 struct T;
781
782 impl Foo for T {{
783     // Comment
784     #[bar]
785     {}
786 }}
787 "#,
788                     hint
789                 ),
790                 &format!(
791                     r#"
792 trait Foo {{
793     type Type;
794     fn function();
795     const CONST: i32 = 0;
796 }}
797 struct T;
798
799 impl Foo for T {{
800     // Comment
801     #[bar]
802     {}
803 }}
804 "#,
805                     completed
806                 ),
807             )
808         };
809         test("function", "fn f$0", "fn function() {\n    $0\n}");
810         test("Type", "type T$0", "type Type = ");
811         test("CONST", "const C$0", "const CONST: i32 = ");
812     }
813
814     #[test]
815     fn generics_are_inlined_in_return_type() {
816         check_edit(
817             "function",
818             r#"
819 trait Foo<T> {
820     fn function() -> T;
821 }
822 struct Bar;
823
824 impl Foo<u32> for Bar {
825     fn f$0
826 }
827 "#,
828             r#"
829 trait Foo<T> {
830     fn function() -> T;
831 }
832 struct Bar;
833
834 impl Foo<u32> for Bar {
835     fn function() -> u32 {
836     $0
837 }
838 }
839 "#,
840         )
841     }
842
843     #[test]
844     fn generics_are_inlined_in_parameter() {
845         check_edit(
846             "function",
847             r#"
848 trait Foo<T> {
849     fn function(bar: T);
850 }
851 struct Bar;
852
853 impl Foo<u32> for Bar {
854     fn f$0
855 }
856 "#,
857             r#"
858 trait Foo<T> {
859     fn function(bar: T);
860 }
861 struct Bar;
862
863 impl Foo<u32> for Bar {
864     fn function(bar: u32) {
865     $0
866 }
867 }
868 "#,
869         )
870     }
871
872     #[test]
873     fn generics_are_inlined_when_part_of_other_types() {
874         check_edit(
875             "function",
876             r#"
877 trait Foo<T> {
878     fn function(bar: Vec<T>);
879 }
880 struct Bar;
881
882 impl Foo<u32> for Bar {
883     fn f$0
884 }
885 "#,
886             r#"
887 trait Foo<T> {
888     fn function(bar: Vec<T>);
889 }
890 struct Bar;
891
892 impl Foo<u32> for Bar {
893     fn function(bar: Vec<u32>) {
894     $0
895 }
896 }
897 "#,
898         )
899     }
900
901     #[test]
902     fn generics_are_inlined_complex() {
903         check_edit(
904             "function",
905             r#"
906 trait Foo<T, U, V> {
907     fn function(bar: Vec<T>, baz: U) -> Arc<Vec<V>>;
908 }
909 struct Bar;
910
911 impl Foo<u32, Vec<usize>, u8> for Bar {
912     fn f$0
913 }
914 "#,
915             r#"
916 trait Foo<T, U, V> {
917     fn function(bar: Vec<T>, baz: U) -> Arc<Vec<V>>;
918 }
919 struct Bar;
920
921 impl Foo<u32, Vec<usize>, u8> for Bar {
922     fn function(bar: Vec<u32>, baz: Vec<usize>) -> Arc<Vec<u8>> {
923     $0
924 }
925 }
926 "#,
927         )
928     }
929
930     #[test]
931     fn generics_are_inlined_in_associated_const() {
932         check_edit(
933             "BAR",
934             r#"
935 trait Foo<T> {
936     const BAR: T;
937 }
938 struct Bar;
939
940 impl Foo<u32> for Bar {
941     const B$0;
942 }
943 "#,
944             r#"
945 trait Foo<T> {
946     const BAR: T;
947 }
948 struct Bar;
949
950 impl Foo<u32> for Bar {
951     const BAR: u32 = ;
952 }
953 "#,
954         )
955     }
956
957     #[test]
958     fn generics_are_inlined_in_where_clause() {
959         check_edit(
960             "function",
961             r#"
962 trait SomeTrait<T> {}
963
964 trait Foo<T> {
965     fn function()
966     where Self: SomeTrait<T>;
967 }
968 struct Bar;
969
970 impl Foo<u32> for Bar {
971     fn f$0
972 }
973 "#,
974             r#"
975 trait SomeTrait<T> {}
976
977 trait Foo<T> {
978     fn function()
979     where Self: SomeTrait<T>;
980 }
981 struct Bar;
982
983 impl Foo<u32> for Bar {
984     fn function()
985 where Self: SomeTrait<u32> {
986     $0
987 }
988 }
989 "#,
990         )
991     }
992 }