diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-10-14 22:41:06 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-10-14 22:41:06 +0000 |
| commit | 3a79af7e277839f803bd0304f28dbe4971ffdad6 (patch) | |
| tree | 457e5a6a94502727d645ee7987c807636041caef | |
| parent | bfb8f73fb3f8a1a7fadfa31bda98a17549a91093 (diff) | |
| parent | bd9bab87ed72779c3bf407137928b75555f5d2a9 (diff) | |
| download | rust-3a79af7e277839f803bd0304f28dbe4971ffdad6.tar.gz rust-3a79af7e277839f803bd0304f28dbe4971ffdad6.zip | |
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 <htilcs1115@gmail.com>
| -rw-r--r-- | crates/ide_assists/src/handlers/replace_if_let_with_match.rs | 31 | ||||
| -rw-r--r-- | crates/ide_assists/src/utils.rs | 41 |
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 4d5262646c8..47d1fbe144a 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 c1092b97c22..6866186d342 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 // |
