diff options
Diffstat (limited to 'crates/ide_assists/src')
-rw-r--r-- | crates/ide_assists/src/handlers/fill_match_arms.rs | 54 |
1 files changed, 37 insertions, 17 deletions
diff --git a/crates/ide_assists/src/handlers/fill_match_arms.rs b/crates/ide_assists/src/handlers/fill_match_arms.rs index 80bd1b7e8..e4794f17c 100644 --- a/crates/ide_assists/src/handlers/fill_match_arms.rs +++ b/crates/ide_assists/src/handlers/fill_match_arms.rs | |||
@@ -1,5 +1,6 @@ | |||
1 | use std::iter; | 1 | use std::iter; |
2 | 2 | ||
3 | use either::Either; | ||
3 | use hir::{Adt, HasSource, ModuleDef, Semantics}; | 4 | use hir::{Adt, HasSource, ModuleDef, Semantics}; |
4 | use ide_db::helpers::{mod_path_to_ast, FamousDefs}; | 5 | use ide_db::helpers::{mod_path_to_ast, FamousDefs}; |
5 | use ide_db::RootDatabase; | 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 | let module = ctx.sema.scope(expr.syntax()).module()?; | 62 | let module = ctx.sema.scope(expr.syntax()).module()?; |
52 | 63 | ||
53 | let missing_arms: Vec<MatchArm> = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr) { | 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 | let mut variants = variants | 67 | let mut variants = variants |
57 | .into_iter() | 68 | .into_iter() |
58 | .filter_map(|variant| build_pat(ctx.db(), module, variant)) | 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 | .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block())) | 71 | .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block())) |
61 | .collect::<Vec<_>>(); | 72 | .collect::<Vec<_>>(); |
62 | if Some(enum_def) == FamousDefs(&ctx.sema, Some(module.krate())).core_option_Option() { | 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 | variants | 78 | variants |
68 | } else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr) { | 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 | // When calculating the match arms for a tuple of enums, we want | 80 | // When calculating the match arms for a tuple of enums, we want |
75 | // to create a match arm for each possible combination of enum | 81 | // to create a match arm for each possible combination of enum |
76 | // values. The `multi_cartesian_product` method transforms | 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 | variants.into_iter().filter_map(|variant| build_pat(ctx.db(), module, variant)); | 91 | variants.into_iter().filter_map(|variant| build_pat(ctx.db(), module, variant)); |
86 | ast::Pat::from(make::tuple_pat(patterns)) | 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 | .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block())) | 95 | .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block())) |
90 | .collect() | 96 | .collect() |
91 | } else { | 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 { | 137 | fn is_variant_missing(existing_pats: &[Pat], var: &Pat) -> bool { |
132 | existing_arms.iter().filter_map(|arm| arm.pat()).all(|pat| { | 138 | !existing_pats.iter().any(|pat| match (pat, var) { |
133 | // Special casee OrPat as separate top-level pats | 139 | (Pat::TuplePat(tpat), Pat::TuplePat(tvar)) => { |
134 | let top_level_pats: Vec<Pat> = match pat { | 140 | // `does_pat_match_variant` gives false positives for tuple patterns |
135 | Pat::OrPat(pats) => pats.pats().collect::<Vec<_>>(), | 141 | // Fixme: this is still somewhat limited |
136 | _ => vec![pat], | 142 | tpat.fields().zip(tvar.fields()).all(|(p, v)| does_pat_match_variant(&p, &v)) |
137 | }; | 143 | } |
138 | 144 | _ => does_pat_match_variant(pat, var), | |
139 | !top_level_pats.iter().any(|pat| does_pat_match_variant(pat, var)) | ||
140 | }) | 145 | }) |
141 | } | 146 | } |
142 | 147 | ||
@@ -467,7 +472,7 @@ fn main() { | |||
467 | 472 | ||
468 | #[test] | 473 | #[test] |
469 | fn fill_match_arms_tuple_of_enum_partial() { | 474 | fn fill_match_arms_tuple_of_enum_partial() { |
470 | check_assist_not_applicable( | 475 | check_assist( |
471 | fill_match_arms, | 476 | fill_match_arms, |
472 | r#" | 477 | r#" |
473 | enum A { One, Two } | 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 | ||