Unnamed repository; edit this file 'description' to name the repository.
Merge #10491
10491: Support nested type on replace if let with match r=k-nasa a=k-nasa ## Why close: https://github.com/rust-analyzer/rust-analyzer/issues/8690 Now, Replacing if-let with match cant't output exhaustive patterns code. This was because the `else` conversion used specific types (ex. Option, Result) instead of wildcards. I thought it was more of a problem to generate non-exhaustive patterns than the benefits of using the concrete one. How about using wildcards in `else`? Is this change policy acceptable? ## What - using wildcards on `make_else_arm` - Change test cases Co-authored-by: k-nasa <[email protected]>
bors[bot] 2021-10-15
parent bfb8f73 · parent bd9bab8 · commit 3a79af7
-rw-r--r--crates/ide_assists/src/handlers/replace_if_let_with_match.rs31
-rw-r--r--crates/ide_assists/src/utils.rs41
2 files changed, 71 insertions, 1 deletions
diff --git a/crates/ide_assists/src/handlers/replace_if_let_with_match.rs b/crates/ide_assists/src/handlers/replace_if_let_with_match.rs
index 4d5262646c..47d1fbe144 100644
--- a/crates/ide_assists/src/handlers/replace_if_let_with_match.rs
+++ b/crates/ide_assists/src/handlers/replace_if_let_with_match.rs
@@ -12,7 +12,7 @@ use syntax::{
};
use crate::{
- utils::{does_pat_match_variant, unwrap_trivial_block},
+ utils::{does_nested_pattern, does_pat_match_variant, unwrap_trivial_block},
AssistContext, AssistId, AssistKind, Assists,
};
@@ -143,6 +143,8 @@ fn make_else_arm(
Some((it, pat)) => {
if does_pat_match_variant(pat, &it.sad_pattern()) {
it.happy_pattern_wildcard()
+ } else if does_nested_pattern(pat) {
+ make::wildcard_pat().into()
} else {
it.sad_pattern()
}
@@ -575,6 +577,33 @@ fn main() {
}
#[test]
+ fn nested_type() {
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+//- minicore: result
+fn foo(x: Result<i32, ()>) {
+ let bar: Result<_, ()> = Ok(Some(1));
+ $0if let Ok(Some(_)) = bar {
+ ()
+ } else {
+ ()
+ }
+}
+"#,
+ r#"
+fn foo(x: Result<i32, ()>) {
+ let bar: Result<_, ()> = Ok(Some(1));
+ match bar {
+ Ok(Some(_)) => (),
+ _ => (),
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
fn test_replace_match_with_if_let_unwraps_simple_expressions() {
check_assist(
replace_match_with_if_let,
diff --git a/crates/ide_assists/src/utils.rs b/crates/ide_assists/src/utils.rs
index c1092b97c2..6866186d34 100644
--- a/crates/ide_assists/src/utils.rs
+++ b/crates/ide_assists/src/utils.rs
@@ -285,6 +285,47 @@ pub(crate) fn does_pat_match_variant(pat: &ast::Pat, var: &ast::Pat) -> bool {
pat_head == var_head
}
+pub(crate) fn does_nested_pattern(pat: &ast::Pat) -> bool {
+ let depth = calc_depth(pat, 0);
+
+ if 1 < depth {
+ return true;
+ }
+ false
+}
+
+fn calc_depth(pat: &ast::Pat, depth: usize) -> usize {
+ match pat {
+ ast::Pat::IdentPat(_)
+ | ast::Pat::BoxPat(_)
+ | ast::Pat::RestPat(_)
+ | ast::Pat::LiteralPat(_)
+ | ast::Pat::MacroPat(_)
+ | ast::Pat::OrPat(_)
+ | ast::Pat::ParenPat(_)
+ | ast::Pat::PathPat(_)
+ | ast::Pat::WildcardPat(_)
+ | ast::Pat::RangePat(_)
+ | ast::Pat::RecordPat(_)
+ | ast::Pat::RefPat(_)
+ | ast::Pat::SlicePat(_)
+ | ast::Pat::TuplePat(_)
+ | ast::Pat::ConstBlockPat(_) => depth,
+
+ // FIXME: Other patterns may also be nested. Currently it simply supports only `TupleStructPat`
+ ast::Pat::TupleStructPat(pat) => {
+ let mut max_depth = depth;
+ for p in pat.fields() {
+ let d = calc_depth(&p, depth + 1);
+ if d > max_depth {
+ max_depth = d
+ }
+ }
+ max_depth
+ }
+ }
+}
+
// Uses a syntax-driven approach to find any impl blocks for the struct that
// exist within the module/file
//