11use std:: iter;
22
3+ use either:: Either ;
34use hir:: { Adt , HasSource , ModuleDef , Semantics } ;
45use ide_db:: helpers:: { mod_path_to_ast, FamousDefs } ;
56use ide_db:: RootDatabase ;
67use itertools:: Itertools ;
78use syntax:: ast:: { self , make, AstNode , MatchArm , NameOwner , Pat } ;
89
910use crate :: {
10- utils:: { does_pat_match_variant , render_snippet, Cursor } ,
11+ utils:: { self , render_snippet, Cursor } ,
1112 AssistContext , AssistId , AssistKind , Assists ,
1213} ;
1314
@@ -48,6 +49,18 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
4849 }
4950 }
5051
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+ // Exclude top level wildcards so that they are expanded by this assist, retains status quo in #8129.
61+ . filter ( |pat| !matches ! ( pat, Pat :: WildcardPat ( _) ) )
62+ . collect ( ) ;
63+
5164 let module = ctx. sema . scope ( expr. syntax ( ) ) . module ( ) ?;
5265
5366 let missing_arms: Vec < MatchArm > = if let Some ( enum_def) = resolve_enum_def ( & ctx. sema , & expr) {
@@ -56,7 +69,7 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
5669 let mut variants = variants
5770 . into_iter ( )
5871 . filter_map ( |variant| build_pat ( ctx. db ( ) , module, variant) )
59- . filter ( |variant_pat| is_variant_missing ( & mut arms , variant_pat) )
72+ . filter ( |variant_pat| is_variant_missing ( & top_lvl_pats , variant_pat) )
6073 . map ( |pat| make:: match_arm ( iter:: once ( pat) , make:: expr_empty_block ( ) ) )
6174 . collect :: < Vec < _ > > ( ) ;
6275 if Some ( enum_def) == FamousDefs ( & ctx. sema , Some ( module. krate ( ) ) ) . core_option_Option ( ) {
@@ -66,11 +79,6 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
6679 }
6780 variants
6881 } 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-
7482 // When calculating the match arms for a tuple of enums, we want
7583 // to create a match arm for each possible combination of enum
7684 // values. The `multi_cartesian_product` method transforms
@@ -85,7 +93,7 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
8593 variants. into_iter ( ) . filter_map ( |variant| build_pat ( ctx. db ( ) , module, variant) ) ;
8694 ast:: Pat :: from ( make:: tuple_pat ( patterns) )
8795 } )
88- . filter ( |variant_pat| is_variant_missing ( & mut arms , variant_pat) )
96+ . filter ( |variant_pat| is_variant_missing ( & top_lvl_pats , variant_pat) )
8997 . map ( |pat| make:: match_arm ( iter:: once ( pat) , make:: expr_empty_block ( ) ) )
9098 . collect ( )
9199 } else {
@@ -128,16 +136,19 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
128136 )
129137}
130138
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- } ;
139+ fn is_variant_missing ( existing_pats : & [ Pat ] , var : & Pat ) -> bool {
140+ !existing_pats. iter ( ) . any ( |pat| does_pat_match_variant ( pat, var) )
141+ }
138142
139- !top_level_pats. iter ( ) . any ( |pat| does_pat_match_variant ( pat, var) )
140- } )
143+ // Fixme: this is still somewhat limited, use hir_ty::diagnostics::match_check?
144+ fn does_pat_match_variant ( pat : & Pat , var : & Pat ) -> bool {
145+ match ( pat, var) {
146+ ( Pat :: WildcardPat ( _) , _) => true ,
147+ ( Pat :: TuplePat ( tpat) , Pat :: TuplePat ( tvar) ) => {
148+ tpat. fields ( ) . zip ( tvar. fields ( ) ) . all ( |( p, v) | does_pat_match_variant ( & p, & v) )
149+ }
150+ _ => utils:: does_pat_match_variant ( pat, var) ,
151+ }
141152}
142153
143154fn resolve_enum_def ( sema : & Semantics < RootDatabase > , expr : & ast:: Expr ) -> Option < hir:: Enum > {
@@ -467,20 +478,81 @@ fn main() {
467478
468479 #[ test]
469480 fn fill_match_arms_tuple_of_enum_partial ( ) {
470- check_assist_not_applicable (
481+ check_assist (
471482 fill_match_arms,
472483 r#"
473- enum A { One, Two }
474- enum B { One, Two }
484+ enum A { One, Two }
485+ enum B { One, Two }
475486
476- fn main() {
477- let a = A::One;
478- let b = B::One;
479- match (a$0, b) {
480- (A::Two, B::One) => {}
481- }
482- }
483- "# ,
487+ fn main() {
488+ let a = A::One;
489+ let b = B::One;
490+ match (a$0, b) {
491+ (A::Two, B::One) => {}
492+ }
493+ }
494+ "# ,
495+ r#"
496+ enum A { One, Two }
497+ enum B { One, Two }
498+
499+ fn main() {
500+ let a = A::One;
501+ let b = B::One;
502+ match (a, b) {
503+ (A::Two, B::One) => {}
504+ $0(A::One, B::One) => {}
505+ (A::One, B::Two) => {}
506+ (A::Two, B::Two) => {}
507+ }
508+ }
509+ "# ,
510+ ) ;
511+ }
512+
513+ #[ test]
514+ fn fill_match_arms_tuple_of_enum_partial_with_wildcards ( ) {
515+ let ra_fixture = r#"
516+ fn main() {
517+ let a = Some(1);
518+ let b = Some(());
519+ match (a$0, b) {
520+ (Some(_), _) => {}
521+ (None, Some(_)) => {}
522+ }
523+ }
524+ "# ;
525+ check_assist (
526+ fill_match_arms,
527+ & format ! ( "//- /main.rs crate:main deps:core{}{}" , ra_fixture, FamousDefs :: FIXTURE ) ,
528+ r#"
529+ fn main() {
530+ let a = Some(1);
531+ let b = Some(());
532+ match (a, b) {
533+ (Some(_), _) => {}
534+ (None, Some(_)) => {}
535+ $0(None, None) => {}
536+ }
537+ }
538+ "# ,
539+ ) ;
540+ }
541+
542+ #[ test]
543+ fn fill_match_arms_partial_with_deep_pattern ( ) {
544+ // Fixme: cannot handle deep patterns
545+ let ra_fixture = r#"
546+ fn main() {
547+ match $0Some(true) {
548+ Some(true) => {}
549+ None => {}
550+ }
551+ }
552+ "# ;
553+ check_assist_not_applicable (
554+ fill_match_arms,
555+ & format ! ( "//- /main.rs crate:main deps:core{}{}" , ra_fixture, FamousDefs :: FIXTURE ) ,
484556 ) ;
485557 }
486558
0 commit comments