2
2
3
3
use std:: iter;
4
4
5
+ use itertools:: Itertools ;
6
+
5
7
use hir:: { Adt , HasSource , Semantics } ;
6
8
use ra_ide_db:: RootDatabase ;
7
9
@@ -39,13 +41,6 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx) -> Option<Assist> {
39
41
let match_arm_list = match_expr. match_arm_list ( ) ?;
40
42
41
43
let expr = match_expr. expr ( ) ?;
42
- let enum_def = resolve_enum_def ( & ctx. sema , & expr) ?;
43
- let module = ctx. sema . scope ( expr. syntax ( ) ) . module ( ) ?;
44
-
45
- let variants = enum_def. variants ( ctx. db ) ;
46
- if variants. is_empty ( ) {
47
- return None ;
48
- }
49
44
50
45
let mut arms: Vec < MatchArm > = match_arm_list. arms ( ) . collect ( ) ;
51
46
if arms. len ( ) == 1 {
@@ -54,13 +49,40 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx) -> Option<Assist> {
54
49
}
55
50
}
56
51
57
- let db = ctx. db ;
58
- let missing_arms: Vec < MatchArm > = variants
59
- . into_iter ( )
60
- . filter_map ( |variant| build_pat ( db, module, variant) )
61
- . filter ( |variant_pat| is_variant_missing ( & mut arms, variant_pat) )
62
- . map ( |pat| make:: match_arm ( iter:: once ( pat) , make:: expr_unit ( ) ) )
63
- . collect ( ) ;
52
+ let module = ctx. sema . scope ( expr. syntax ( ) ) . module ( ) ?;
53
+
54
+ let missing_arms: Vec < MatchArm > = if let Some ( enum_def) = resolve_enum_def ( & ctx. sema , & expr) {
55
+ let variants = enum_def. variants ( ctx. db ) ;
56
+
57
+ variants
58
+ . into_iter ( )
59
+ . filter_map ( |variant| build_pat ( ctx. db , module, variant) )
60
+ . filter ( |variant_pat| is_variant_missing ( & mut arms, variant_pat) )
61
+ . map ( |pat| make:: match_arm ( iter:: once ( pat) , make:: expr_unit ( ) ) )
62
+ . collect ( )
63
+ } else if let Some ( enum_defs) = resolve_tuple_of_enum_def ( & ctx. sema , & expr) {
64
+ // partial fill not currently supported for tuple of enums
65
+ if !arms. is_empty ( ) {
66
+ return None ;
67
+ }
68
+
69
+ enum_defs
70
+ . into_iter ( )
71
+ . map ( |enum_def| enum_def. variants ( ctx. db ) )
72
+ . multi_cartesian_product ( )
73
+ . map ( |variants| {
74
+ let patterns = variants
75
+ . into_iter ( )
76
+ . filter_map ( |variant| build_pat ( ctx. db , module, variant) )
77
+ . collect :: < Vec < _ > > ( ) ;
78
+ ast:: Pat :: from ( make:: tuple_pat ( patterns) )
79
+ } )
80
+ . filter ( |variant_pat| is_variant_missing ( & mut arms, variant_pat) )
81
+ . map ( |pat| make:: match_arm ( iter:: once ( pat) , make:: expr_unit ( ) ) )
82
+ . collect ( )
83
+ } else {
84
+ return None ;
85
+ } ;
64
86
65
87
if missing_arms. is_empty ( ) {
66
88
return None ;
@@ -104,6 +126,22 @@ fn resolve_enum_def(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<
104
126
} )
105
127
}
106
128
129
+ fn resolve_tuple_of_enum_def (
130
+ sema : & Semantics < RootDatabase > ,
131
+ expr : & ast:: Expr ,
132
+ ) -> Option < Vec < hir:: Enum > > {
133
+ Some (
134
+ sema. type_of_expr ( & expr) ?
135
+ . tuple_fields ( sema. db )
136
+ . iter ( )
137
+ . map ( |ty| match ty. as_adt ( ) {
138
+ Some ( Adt :: Enum ( e) ) => e,
139
+ _ => panic ! ( "handle the case of tuple containing non-enum" ) ,
140
+ } )
141
+ . collect ( ) ,
142
+ )
143
+ }
144
+
107
145
fn build_pat ( db : & RootDatabase , module : hir:: Module , var : hir:: EnumVariant ) -> Option < ast:: Pat > {
108
146
let path = crate :: ast_transform:: path_to_ast ( module. find_use_path ( db, var. into ( ) ) ?) ;
109
147
@@ -307,6 +345,103 @@ mod tests {
307
345
) ;
308
346
}
309
347
348
+ #[ test]
349
+ fn fill_match_arms_tuple_of_enum ( ) {
350
+ check_assist (
351
+ fill_match_arms,
352
+ r#"
353
+ enum A {
354
+ One,
355
+ Two,
356
+ }
357
+ enum B {
358
+ One,
359
+ Two,
360
+ }
361
+
362
+ fn main() {
363
+ let a = A::One;
364
+ let b = B::One;
365
+ match (a<|>, b) {}
366
+ }
367
+ "# ,
368
+ r#"
369
+ enum A {
370
+ One,
371
+ Two,
372
+ }
373
+ enum B {
374
+ One,
375
+ Two,
376
+ }
377
+
378
+ fn main() {
379
+ let a = A::One;
380
+ let b = B::One;
381
+ match <|>(a, b) {
382
+ (A::One, B::One) => (),
383
+ (A::One, B::Two) => (),
384
+ (A::Two, B::One) => (),
385
+ (A::Two, B::Two) => (),
386
+ }
387
+ }
388
+ "# ,
389
+ ) ;
390
+ }
391
+
392
+ #[ test]
393
+ fn fill_match_arms_tuple_of_enum_partial ( ) {
394
+ check_assist_not_applicable (
395
+ fill_match_arms,
396
+ r#"
397
+ enum A {
398
+ One,
399
+ Two,
400
+ }
401
+ enum B {
402
+ One,
403
+ Two,
404
+ }
405
+
406
+ fn main() {
407
+ let a = A::One;
408
+ let b = B::One;
409
+ match (a<|>, b) {
410
+ (A::Two, B::One) => (),
411
+ }
412
+ }
413
+ "# ,
414
+ ) ;
415
+ }
416
+
417
+ #[ test]
418
+ fn fill_match_arms_tuple_of_enum_not_applicable ( ) {
419
+ check_assist_not_applicable (
420
+ fill_match_arms,
421
+ r#"
422
+ enum A {
423
+ One,
424
+ Two,
425
+ }
426
+ enum B {
427
+ One,
428
+ Two,
429
+ }
430
+
431
+ fn main() {
432
+ let a = A::One;
433
+ let b = B::One;
434
+ match (a<|>, b) {
435
+ (A::Two, B::One) => (),
436
+ (A::One, B::One) => (),
437
+ (A::One, B::Two) => (),
438
+ (A::Two, B::Two) => (),
439
+ }
440
+ }
441
+ "# ,
442
+ ) ;
443
+ }
444
+
310
445
#[ test]
311
446
fn test_fill_match_arm_refs ( ) {
312
447
check_assist (
0 commit comments