@@ -109,7 +109,13 @@ pub(crate) fn signature_help(db: &RootDatabase, position: FilePosition) -> Optio
109109 }
110110 return signature_help_for_record_pat( & sema, record, token) ;
111111 } ,
112- ast:: TupleStructPat ( tuple_pat) => { } ,
112+ ast:: TupleStructPat ( tuple_pat) => {
113+ let cursor_outside = tuple_pat. r_paren_token( ) . as_ref( ) == Some ( & token) ;
114+ if cursor_outside {
115+ continue ;
116+ }
117+ return signature_help_for_tuple_struct_pat( & sema, tuple_pat, token) ;
118+ } ,
113119 _ => ( ) ,
114120 }
115121 }
@@ -367,6 +373,90 @@ fn signature_help_for_record_lit(
367373 )
368374}
369375
376+ fn signature_help_for_record_pat (
377+ sema : & Semantics < ' _ , RootDatabase > ,
378+ record : ast:: RecordPat ,
379+ token : SyntaxToken ,
380+ ) -> Option < SignatureHelp > {
381+ signature_help_for_record_ (
382+ sema,
383+ record. record_pat_field_list ( ) ?. syntax ( ) . children_with_tokens ( ) ,
384+ & record. path ( ) ?,
385+ record
386+ . record_pat_field_list ( ) ?
387+ . fields ( )
388+ . filter_map ( |field| sema. resolve_record_pat_field ( & field) ) ,
389+ token,
390+ )
391+ }
392+
393+ fn signature_help_for_tuple_struct_pat (
394+ sema : & Semantics < ' _ , RootDatabase > ,
395+ pat : ast:: TupleStructPat ,
396+ token : SyntaxToken ,
397+ ) -> Option < SignatureHelp > {
398+ let rest_pat = pat. fields ( ) . find ( |it| matches ! ( it, ast:: Pat :: RestPat ( _) ) ) ;
399+ let is_left_of_rest_pat =
400+ rest_pat. map_or ( true , |it| token. text_range ( ) . start ( ) < it. syntax ( ) . text_range ( ) . end ( ) ) ;
401+
402+ let mut res = SignatureHelp {
403+ doc : None ,
404+ signature : String :: new ( ) ,
405+ parameters : vec ! [ ] ,
406+ active_parameter : None ,
407+ } ;
408+
409+ let db = sema. db ;
410+ let path_res = sema. resolve_path ( & pat. path ( ) ?) ?;
411+ let fields: Vec < _ > = if let PathResolution :: Def ( ModuleDef :: Variant ( variant) ) = path_res {
412+ let en = variant. parent_enum ( db) ;
413+
414+ res. doc = en. docs ( db) . map ( |it| it. into ( ) ) ;
415+ format_to ! ( res. signature, "enum {}::{} (" , en. name( db) , variant. name( db) ) ;
416+ variant. fields ( db)
417+ } else {
418+ let adt = match path_res {
419+ PathResolution :: SelfType ( imp) => imp. self_ty ( db) . as_adt ( ) ?,
420+ PathResolution :: Def ( ModuleDef :: Adt ( adt) ) => adt,
421+ _ => return None ,
422+ } ;
423+
424+ match adt {
425+ hir:: Adt :: Struct ( it) => {
426+ res. doc = it. docs ( db) . map ( |it| it. into ( ) ) ;
427+ format_to ! ( res. signature, "struct {} (" , it. name( db) ) ;
428+ it. fields ( db)
429+ }
430+ _ => return None ,
431+ }
432+ } ;
433+ let commas = pat
434+ . syntax ( )
435+ . children_with_tokens ( )
436+ . filter_map ( syntax:: NodeOrToken :: into_token)
437+ . filter ( |t| t. kind ( ) == syntax:: T ![ , ] ) ;
438+ res. active_parameter = Some ( if is_left_of_rest_pat {
439+ commas. take_while ( |t| t. text_range ( ) . start ( ) <= token. text_range ( ) . start ( ) ) . count ( )
440+ } else {
441+ let n_commas = commas
442+ . collect :: < Vec < _ > > ( )
443+ . into_iter ( )
444+ . rev ( )
445+ . take_while ( |t| t. text_range ( ) . start ( ) > token. text_range ( ) . start ( ) )
446+ . count ( ) ;
447+ fields. len ( ) . saturating_sub ( 1 ) . saturating_sub ( n_commas)
448+ } ) ;
449+
450+ let mut buf = String :: new ( ) ;
451+ for ty in fields. into_iter ( ) . map ( |it| it. ty ( db) ) {
452+ format_to ! ( buf, "{}" , ty. display_truncated( db, Some ( 20 ) ) ) ;
453+ res. push_call_param ( & buf) ;
454+ buf. clear ( ) ;
455+ }
456+ res. signature . push_str ( ")" ) ;
457+ Some ( res)
458+ }
459+
370460fn signature_help_for_record_ (
371461 sema : & Semantics < ' _ , RootDatabase > ,
372462 field_list_children : SyntaxElementChildren ,
@@ -442,23 +532,6 @@ fn signature_help_for_record_(
442532 Some ( res)
443533}
444534
445- fn signature_help_for_record_pat (
446- sema : & Semantics < ' _ , RootDatabase > ,
447- record : ast:: RecordPat ,
448- token : SyntaxToken ,
449- ) -> Option < SignatureHelp > {
450- signature_help_for_record_ (
451- sema,
452- record. record_pat_field_list ( ) ?. syntax ( ) . children_with_tokens ( ) ,
453- & record. path ( ) ?,
454- record
455- . record_pat_field_list ( ) ?
456- . fields ( )
457- . filter_map ( |field| sema. resolve_record_pat_field ( & field) ) ,
458- token,
459- )
460- }
461-
462535#[ cfg( test) ]
463536mod tests {
464537 use std:: iter;
@@ -480,6 +553,7 @@ mod tests {
480553 ( database, FilePosition { file_id, offset } )
481554 }
482555
556+ #[ track_caller]
483557 fn check ( ra_fixture : & str , expect : Expect ) {
484558 let fixture = format ! (
485559 r#"
@@ -931,6 +1005,119 @@ fn main() {
9311005 ) ;
9321006 }
9331007
1008+ #[ test]
1009+ fn tuple_struct_pat ( ) {
1010+ check (
1011+ r#"
1012+ /// A cool tuple struct
1013+ struct S(u32, i32);
1014+ fn main() {
1015+ let S(0, $0);
1016+ }
1017+ "# ,
1018+ expect ! [ [ r#"
1019+ A cool tuple struct
1020+ ------
1021+ struct S (u32, i32)
1022+ --- ^^^
1023+ "# ] ] ,
1024+ ) ;
1025+ }
1026+
1027+ #[ test]
1028+ fn tuple_struct_pat_rest ( ) {
1029+ check (
1030+ r#"
1031+ /// A cool tuple struct
1032+ struct S(u32, i32, f32, u16);
1033+ fn main() {
1034+ let S(0, .., $0);
1035+ }
1036+ "# ,
1037+ expect ! [ [ r#"
1038+ A cool tuple struct
1039+ ------
1040+ struct S (u32, i32, f32, u16)
1041+ --- --- --- ^^^
1042+ "# ] ] ,
1043+ ) ;
1044+ check (
1045+ r#"
1046+ /// A cool tuple struct
1047+ struct S(u32, i32, f32, u16, u8);
1048+ fn main() {
1049+ let S(0, .., $0, 0);
1050+ }
1051+ "# ,
1052+ expect ! [ [ r#"
1053+ A cool tuple struct
1054+ ------
1055+ struct S (u32, i32, f32, u16, u8)
1056+ --- --- --- ^^^ --
1057+ "# ] ] ,
1058+ ) ;
1059+ check (
1060+ r#"
1061+ /// A cool tuple struct
1062+ struct S(u32, i32, f32, u16);
1063+ fn main() {
1064+ let S($0, .., 1);
1065+ }
1066+ "# ,
1067+ expect ! [ [ r#"
1068+ A cool tuple struct
1069+ ------
1070+ struct S (u32, i32, f32, u16)
1071+ ^^^ --- --- ---
1072+ "# ] ] ,
1073+ ) ;
1074+ check (
1075+ r#"
1076+ /// A cool tuple struct
1077+ struct S(u32, i32, f32, u16, u8);
1078+ fn main() {
1079+ let S(1, .., 1, $0, 2);
1080+ }
1081+ "# ,
1082+ expect ! [ [ r#"
1083+ A cool tuple struct
1084+ ------
1085+ struct S (u32, i32, f32, u16, u8)
1086+ --- --- --- ^^^ --
1087+ "# ] ] ,
1088+ ) ;
1089+ check (
1090+ r#"
1091+ /// A cool tuple struct
1092+ struct S(u32, i32, f32, u16);
1093+ fn main() {
1094+ let S(1, $0.., 1);
1095+ }
1096+ "# ,
1097+ expect ! [ [ r#"
1098+ A cool tuple struct
1099+ ------
1100+ struct S (u32, i32, f32, u16)
1101+ --- ^^^ --- ---
1102+ "# ] ] ,
1103+ ) ;
1104+ check (
1105+ r#"
1106+ /// A cool tuple struct
1107+ struct S(u32, i32, f32, u16);
1108+ fn main() {
1109+ let S(1, ..$0, 1);
1110+ }
1111+ "# ,
1112+ expect ! [ [ r#"
1113+ A cool tuple struct
1114+ ------
1115+ struct S (u32, i32, f32, u16)
1116+ --- ^^^ --- ---
1117+ "# ] ] ,
1118+ ) ;
1119+ }
1120+
9341121 #[ test]
9351122 fn generic_struct ( ) {
9361123 check (
0 commit comments