1
1
use std:: iter;
2
2
3
+ use either:: Either ;
3
4
use hir:: { Adt , HasSource , ModuleDef , Semantics } ;
4
5
use ide_db:: helpers:: { mod_path_to_ast, FamousDefs } ;
5
6
use ide_db:: RootDatabase ;
@@ -48,6 +49,16 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
48
49
}
49
50
}
50
51
52
+ let top_lvl_pats: Vec < _ > = arms
53
+ . iter ( )
54
+ . filter_map ( ast:: MatchArm :: pat)
55
+ . flat_map ( |pat| match pat {
56
+ // Special casee OrPat as separate top-level pats
57
+ Pat :: OrPat ( or_pat) => Either :: Left ( or_pat. pats ( ) ) ,
58
+ _ => Either :: Right ( iter:: once ( pat) ) ,
59
+ } )
60
+ . collect ( ) ;
61
+
51
62
let module = ctx. sema . scope ( expr. syntax ( ) ) . module ( ) ?;
52
63
53
64
let missing_arms: Vec < MatchArm > = if let Some ( enum_def) = resolve_enum_def ( & ctx. sema , & expr) {
@@ -56,7 +67,7 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
56
67
let mut variants = variants
57
68
. into_iter ( )
58
69
. filter_map ( |variant| build_pat ( ctx. db ( ) , module, variant) )
59
- . filter ( |variant_pat| is_variant_missing ( & mut arms , variant_pat) )
70
+ . filter ( |variant_pat| is_variant_missing ( & top_lvl_pats , variant_pat) )
60
71
. map ( |pat| make:: match_arm ( iter:: once ( pat) , make:: expr_empty_block ( ) ) )
61
72
. collect :: < Vec < _ > > ( ) ;
62
73
if Some ( enum_def) == FamousDefs ( & ctx. sema , Some ( module. krate ( ) ) ) . core_option_Option ( ) {
@@ -66,11 +77,6 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
66
77
}
67
78
variants
68
79
} else if let Some ( enum_defs) = resolve_tuple_of_enum_def ( & ctx. sema , & expr) {
69
- // Partial fill not currently supported for tuple of enums.
70
- if !arms. is_empty ( ) {
71
- return None ;
72
- }
73
-
74
80
// When calculating the match arms for a tuple of enums, we want
75
81
// to create a match arm for each possible combination of enum
76
82
// values. The `multi_cartesian_product` method transforms
@@ -85,7 +91,7 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
85
91
variants. into_iter ( ) . filter_map ( |variant| build_pat ( ctx. db ( ) , module, variant) ) ;
86
92
ast:: Pat :: from ( make:: tuple_pat ( patterns) )
87
93
} )
88
- . filter ( |variant_pat| is_variant_missing ( & mut arms , variant_pat) )
94
+ . filter ( |variant_pat| is_variant_missing ( & top_lvl_pats , variant_pat) )
89
95
. map ( |pat| make:: match_arm ( iter:: once ( pat) , make:: expr_empty_block ( ) ) )
90
96
. collect ( )
91
97
} else {
@@ -128,15 +134,14 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
128
134
)
129
135
}
130
136
131
- fn is_variant_missing ( existing_arms : & mut Vec < MatchArm > , var : & Pat ) -> bool {
132
- existing_arms. iter ( ) . filter_map ( |arm| arm. pat ( ) ) . all ( |pat| {
133
- // Special casee OrPat as separate top-level pats
134
- let top_level_pats: Vec < Pat > = match pat {
135
- Pat :: OrPat ( pats) => pats. pats ( ) . collect :: < Vec < _ > > ( ) ,
136
- _ => vec ! [ pat] ,
137
- } ;
138
-
139
- !top_level_pats. iter ( ) . any ( |pat| does_pat_match_variant ( pat, var) )
137
+ fn is_variant_missing ( existing_pats : & [ Pat ] , var : & Pat ) -> bool {
138
+ !existing_pats. iter ( ) . any ( |pat| match ( pat, var) {
139
+ ( Pat :: TuplePat ( tpat) , Pat :: TuplePat ( tvar) ) => {
140
+ // `does_pat_match_variant` gives false positives for tuple patterns
141
+ // Fixme: this is still somewhat limited
142
+ tpat. fields ( ) . zip ( tvar. fields ( ) ) . all ( |( p, v) | does_pat_match_variant ( & p, & v) )
143
+ }
144
+ _ => does_pat_match_variant ( pat, var) ,
140
145
} )
141
146
}
142
147
@@ -467,7 +472,7 @@ fn main() {
467
472
468
473
#[ test]
469
474
fn fill_match_arms_tuple_of_enum_partial ( ) {
470
- check_assist_not_applicable (
475
+ check_assist (
471
476
fill_match_arms,
472
477
r#"
473
478
enum A { One, Two }
@@ -481,6 +486,21 @@ fn main() {
481
486
}
482
487
}
483
488
"# ,
489
+ r#"
490
+ enum A { One, Two }
491
+ enum B { One, Two }
492
+
493
+ fn main() {
494
+ let a = A::One;
495
+ let b = B::One;
496
+ match (a, b) {
497
+ (A::Two, B::One) => {}
498
+ $0(A::One, B::One) => {}
499
+ (A::One, B::Two) => {}
500
+ (A::Two, B::Two) => {}
501
+ }
502
+ }
503
+ "# ,
484
504
) ;
485
505
}
486
506
0 commit comments