Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-assists/src/handlers/replace_if_let_with_match.rs')
-rw-r--r--crates/ide-assists/src/handlers/replace_if_let_with_match.rs720
1 files changed, 707 insertions, 13 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 56dd6cf29a..b31d45e6d4 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
@@ -17,7 +17,7 @@ use syntax::{
};
use crate::{
- utils::{does_nested_pattern, does_pat_match_variant, unwrap_trivial_block},
+ utils::{does_pat_match_variant, does_pat_variant_nested_or_literal, unwrap_trivial_block},
AssistContext, AssistId, AssistKind, Assists,
};
@@ -135,7 +135,7 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext<'
};
let has_preceding_if_expr =
- if_expr.syntax().parent().map_or(false, |it| ast::IfExpr::can_cast(it.kind()));
+ if_expr.syntax().parent().is_some_and(|it| ast::IfExpr::can_cast(it.kind()));
let expr = if has_preceding_if_expr {
// make sure we replace the `else if let ...` with a block so we don't end up with `else expr`
make::block_expr(None, Some(match_expr)).into()
@@ -163,7 +163,7 @@ fn make_else_arm(
Some(it) => {
if does_pat_match_variant(pat, &it.sad_pattern()) {
it.happy_pattern_wildcard()
- } else if does_nested_pattern(pat) {
+ } else if does_pat_variant_nested_or_literal(ctx, pat) {
make::wildcard_pat().into()
} else {
it.sad_pattern()
@@ -241,7 +241,7 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'
ast::Pat::LiteralPat(p)
if p.literal()
.map(|it| it.token().kind())
- .map_or(false, |it| it == T![true] || it == T![false]) =>
+ .is_some_and(|it| it == T![true] || it == T![false]) =>
{
""
}
@@ -265,12 +265,12 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'
let condition = match if_let_pat {
ast::Pat::LiteralPat(p)
- if p.literal().map_or(false, |it| it.token().kind() == T![true]) =>
+ if p.literal().is_some_and(|it| it.token().kind() == T![true]) =>
{
scrutinee
}
ast::Pat::LiteralPat(p)
- if p.literal().map_or(false, |it| it.token().kind() == T![false]) =>
+ if p.literal().is_some_and(|it| it.token().kind() == T![false]) =>
{
make::expr_prefix(T![!], scrutinee)
}
@@ -339,10 +339,10 @@ fn binds_name(sema: &hir::Semantics<'_, RootDatabase>, pat: &ast::Pat) -> bool {
ast::Pat::TupleStructPat(it) => it.fields().any(binds_name_v),
ast::Pat::RecordPat(it) => it
.record_pat_field_list()
- .map_or(false, |rpfl| rpfl.fields().flat_map(|rpf| rpf.pat()).any(binds_name_v)),
- ast::Pat::RefPat(pat) => pat.pat().map_or(false, binds_name_v),
- ast::Pat::BoxPat(pat) => pat.pat().map_or(false, binds_name_v),
- ast::Pat::ParenPat(pat) => pat.pat().map_or(false, binds_name_v),
+ .is_some_and(|rpfl| rpfl.fields().flat_map(|rpf| rpf.pat()).any(binds_name_v)),
+ ast::Pat::RefPat(pat) => pat.pat().is_some_and(binds_name_v),
+ ast::Pat::BoxPat(pat) => pat.pat().is_some_and(binds_name_v),
+ ast::Pat::ParenPat(pat) => pat.pat().is_some_and(binds_name_v),
_ => false,
}
}
@@ -350,7 +350,7 @@ fn binds_name(sema: &hir::Semantics<'_, RootDatabase>, pat: &ast::Pat) -> bool {
fn is_sad_pat(sema: &hir::Semantics<'_, RootDatabase>, pat: &ast::Pat) -> bool {
sema.type_of_pat(pat)
.and_then(|ty| TryEnum::from_ty(sema, &ty.adjusted()))
- .map_or(false, |it| does_pat_match_variant(pat, &it.sad_pattern()))
+ .is_some_and(|it| does_pat_match_variant(pat, &it.sad_pattern()))
}
#[cfg(test)]
@@ -702,11 +702,11 @@ fn main() {
}
#[test]
- fn nested_type() {
+ fn test_if_let_with_match_nested_tuple_struct() {
check_assist(
replace_if_let_with_match,
r#"
-//- minicore: result
+//- minicore: result, option
fn foo(x: Result<i32, ()>) {
let bar: Result<_, ()> = Ok(Some(1));
$0if let Ok(Some(_)) = bar {
@@ -726,6 +726,700 @@ fn foo(x: Result<i32, ()>) {
}
"#,
);
+
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+//- minicore: result
+struct MyStruct(i32, i32);
+fn foo(x: Result<MyStruct, ()>) {
+ let bar: Result<MyStruct, ()> = Ok(MyStruct(1, 2));
+ $0if let Ok(MyStruct(a, b)) = bar {
+ ()
+ } else {
+ ()
+ }
+}
+"#,
+ r#"
+struct MyStruct(i32, i32);
+fn foo(x: Result<MyStruct, ()>) {
+ let bar: Result<MyStruct, ()> = Ok(MyStruct(1, 2));
+ match bar {
+ Ok(MyStruct(a, b)) => (),
+ Err(_) => (),
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn test_if_let_with_match_nested_slice() {
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+//- minicore: result
+fn foo(x: Result<&[i32], ()>) {
+ let foo: Result<&[_], ()> = Ok(&[0, 1, 2]);
+ $0if let Ok([]) = foo {
+ ()
+ } else {
+ ()
+ }
+}
+ "#,
+ r#"
+fn foo(x: Result<&[i32], ()>) {
+ let foo: Result<&[_], ()> = Ok(&[0, 1, 2]);
+ match foo {
+ Ok([]) => (),
+ _ => (),
+ }
+}
+ "#,
+ );
+
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+//- minicore: result
+fn foo(x: Result<[&'static str; 2], ()>) {
+ let foobar: Result<_, ()> = Ok(["foo", "bar"]);
+ $0if let Ok([_, "bar"]) = foobar {
+ ()
+ } else {
+ ()
+ }
+}
+"#,
+ r#"
+fn foo(x: Result<[&'static str; 2], ()>) {
+ let foobar: Result<_, ()> = Ok(["foo", "bar"]);
+ match foobar {
+ Ok([_, "bar"]) => (),
+ _ => (),
+ }
+}
+"#,
+ );
+
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+//- minicore: result
+fn foo(x: Result<[&'static str; 2], ()>) {
+ let foobar: Result<_, ()> = Ok(["foo", "bar"]);
+ $0if let Ok([..]) = foobar {
+ ()
+ } else {
+ ()
+ }
+}
+"#,
+ r#"
+fn foo(x: Result<[&'static str; 2], ()>) {
+ let foobar: Result<_, ()> = Ok(["foo", "bar"]);
+ match foobar {
+ Ok([..]) => (),
+ Err(_) => (),
+ }
+}
+"#,
+ );
+
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+//- minicore: result
+fn foo(x: Result<&[&'static str], ()>) {
+ let foobar: Result<&[&'static str], ()> = Ok(&["foo", "bar"]);
+ $0if let Ok([a, ..]) = foobar {
+ ()
+ } else {
+ ()
+ }
+}
+"#,
+ r#"
+fn foo(x: Result<&[&'static str], ()>) {
+ let foobar: Result<&[&'static str], ()> = Ok(&["foo", "bar"]);
+ match foobar {
+ Ok([a, ..]) => (),
+ _ => (),
+ }
+}
+"#,
+ );
+
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+//- minicore: result
+fn foo(x: Result<&[&'static str], ()>) {
+ let foobar: Result<&[&'static str], ()> = Ok(&["foo", "bar"]);
+ $0if let Ok([a, .., b, c]) = foobar {
+ ()
+ } else {
+ ()
+ }
+}
+"#,
+ r#"
+fn foo(x: Result<&[&'static str], ()>) {
+ let foobar: Result<&[&'static str], ()> = Ok(&["foo", "bar"]);
+ match foobar {
+ Ok([a, .., b, c]) => (),
+ _ => (),
+ }
+}
+"#,
+ );
+
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+//- minicore: result
+fn foo(x: Result<Option<[&'static str; 2]>, ()>) {
+ let foobar: Result<_, ()> = Ok(Some(["foo", "bar"]));
+ $0if let Ok(Some([_, "bar"])) = foobar {
+ ()
+ } else {
+ ()
+ }
+}
+"#,
+ r#"
+fn foo(x: Result<Option<[&'static str; 2]>, ()>) {
+ let foobar: Result<_, ()> = Ok(Some(["foo", "bar"]));
+ match foobar {
+ Ok(Some([_, "bar"])) => (),
+ _ => (),
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn test_if_let_with_match_nested_literal() {
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+//- minicore: result
+fn foo(x: Result<&'static str, ()>) {
+ let bar: Result<&_, ()> = Ok("bar");
+ $0if let Ok("foo") = bar {
+ ()
+ } else {
+ ()
+ }
+}
+"#,
+ r#"
+fn foo(x: Result<&'static str, ()>) {
+ let bar: Result<&_, ()> = Ok("bar");
+ match bar {
+ Ok("foo") => (),
+ _ => (),
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn test_if_let_with_match_nested_tuple() {
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+//- minicore: result
+fn foo(x: Result<(i32, i32, i32), ()>) {
+ let bar: Result<(i32, i32, i32), ()> = Ok((1, 2, 3));
+ $0if let Ok((1, second, third)) = bar {
+ ()
+ } else {
+ ()
+ }
+}
+"#,
+ r#"
+fn foo(x: Result<(i32, i32, i32), ()>) {
+ let bar: Result<(i32, i32, i32), ()> = Ok((1, 2, 3));
+ match bar {
+ Ok((1, second, third)) => (),
+ _ => (),
+ }
+}
+"#,
+ );
+
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+//- minicore: result
+fn foo(x: Result<(i32, i32, i32), ()>) {
+ let bar: Result<(i32, i32, i32), ()> = Ok((1, 2, 3));
+ $0if let Ok((first, second, third)) = bar {
+ ()
+ } else {
+ ()
+ }
+}
+"#,
+ r#"
+fn foo(x: Result<(i32, i32, i32), ()>) {
+ let bar: Result<(i32, i32, i32), ()> = Ok((1, 2, 3));
+ match bar {
+ Ok((first, second, third)) => (),
+ Err(_) => (),
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn test_if_let_with_match_nested_or() {
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+//- minicore: result
+fn foo(x: Result<i32, ()>) {
+ let bar: Result<i32, ()> = Ok(1);
+ $0if let Ok(1 | 2) = bar {
+ ()
+ } else {
+ ()
+ }
+}
+"#,
+ r#"
+fn foo(x: Result<i32, ()>) {
+ let bar: Result<i32, ()> = Ok(1);
+ match bar {
+ Ok(1 | 2) => (),
+ _ => (),
+ }
+}
+"#,
+ );
+
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+//- minicore: result
+fn foo(x: Result<(i32, i32), ()>) {
+ let bar: Result<(i32, i32), ()> = Ok((1, 2));
+ $0if let Ok((b, a) | (a, b)) = bar {
+ ()
+ } else {
+ ()
+ }
+}
+"#,
+ r#"
+fn foo(x: Result<(i32, i32), ()>) {
+ let bar: Result<(i32, i32), ()> = Ok((1, 2));
+ match bar {
+ Ok((b, a) | (a, b)) => (),
+ Err(_) => (),
+ }
+}
+"#,
+ );
+
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+//- minicore: result
+fn foo(x: Result<(i32, i32), ()>) {
+ let bar: Result<(i32, i32), ()> = Ok((1, 2));
+ $0if let Ok((1, a) | (a, 2)) = bar {
+ ()
+ } else {
+ ()
+ }
+}
+"#,
+ r#"
+fn foo(x: Result<(i32, i32), ()>) {
+ let bar: Result<(i32, i32), ()> = Ok((1, 2));
+ match bar {
+ Ok((1, a) | (a, 2)) => (),
+ _ => (),
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn test_if_let_with_match_nested_range() {
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+//- minicore: result
+fn foo(x: Result<i32, ()>) {
+ let bar: Result<i32, ()> = Ok(1);
+ $0if let Ok(1..2) = bar {
+ ()
+ } else {
+ ()
+ }
+}
+"#,
+ r#"
+fn foo(x: Result<i32, ()>) {
+ let bar: Result<i32, ()> = Ok(1);
+ match bar {
+ Ok(1..2) => (),
+ _ => (),
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn test_if_let_with_match_nested_paren() {
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+//- minicore: result
+fn foo(x: Result<(i32, i32), ()>) {
+ let bar: Result<(i32, i32), ()> = Ok((1, 1));
+ $0if let Ok(((1, 2))) = bar {
+ ()
+ } else {
+ ()
+ }
+}
+"#,
+ r#"
+fn foo(x: Result<(i32, i32), ()>) {
+ let bar: Result<(i32, i32), ()> = Ok((1, 1));
+ match bar {
+ Ok(((1, 2))) => (),
+ _ => (),
+ }
+}
+"#,
+ );
+
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+//- minicore: result
+fn foo(x: Result<(i32, i32), ()>) {
+ let bar: Result<(i32, i32), ()> = Ok((1, 1));
+ $0if let Ok(((a, b))) = bar {
+ ()
+ } else {
+ ()
+ }
+}
+"#,
+ r#"
+fn foo(x: Result<(i32, i32), ()>) {
+ let bar: Result<(i32, i32), ()> = Ok((1, 1));
+ match bar {
+ Ok(((a, b))) => (),
+ Err(_) => (),
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn test_if_let_with_match_nested_macro() {
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+//- minicore: result
+fn foo(x: Result<i32, ()>) {
+ macro_rules! is_42 {
+ () => {
+ 42
+ };
+ }
+
+ let bar: Result<i32, ()> = Ok(1);
+ $0if let Ok(is_42!()) = bar {
+ ()
+ } else {
+ ()
+ }
+}
+"#,
+ r#"
+fn foo(x: Result<i32, ()>) {
+ macro_rules! is_42 {
+ () => {
+ 42
+ };
+ }
+
+ let bar: Result<i32, ()> = Ok(1);
+ match bar {
+ Ok(is_42!()) => (),
+ _ => (),
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn test_if_let_with_match_nested_path() {
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+//- minicore: result
+enum MyEnum {
+ Foo,
+ Bar,
+}
+
+fn foo(x: Result<MyEnum, ()>) {
+ let bar: Result<MyEnum, ()> = Ok(MyEnum::Foo);
+ $0if let Ok(MyEnum::Foo) = bar {
+ ()
+ } else {
+ ()
+ }
+}
+"#,
+ r#"
+enum MyEnum {
+ Foo,
+ Bar,
+}
+
+fn foo(x: Result<MyEnum, ()>) {
+ let bar: Result<MyEnum, ()> = Ok(MyEnum::Foo);
+ match bar {
+ Ok(MyEnum::Foo) => (),
+ _ => (),
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn test_if_let_with_match_nested_record() {
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+//- minicore: result
+struct MyStruct {
+ foo: i32,
+ bar: i32,
+}
+
+fn foo(x: Result<MyStruct, ()>) {
+ let bar: Result<MyStruct, ()> = Ok(MyStruct { foo: 1, bar: 2 });
+ $0if let Ok(MyStruct { foo, bar }) = bar {
+ ()
+ } else {
+ ()
+ }
+}
+"#,
+ r#"
+struct MyStruct {
+ foo: i32,
+ bar: i32,
+}
+
+fn foo(x: Result<MyStruct, ()>) {
+ let bar: Result<MyStruct, ()> = Ok(MyStruct { foo: 1, bar: 2 });
+ match bar {
+ Ok(MyStruct { foo, bar }) => (),
+ Err(_) => (),
+ }
+}
+"#,
+ );
+
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+//- minicore: result
+struct MyStruct {
+ foo: i32,
+ bar: i32,
+}
+
+fn foo(x: Result<MyStruct, ()>) {
+ let bar: Result<MyStruct, ()> = Ok(MyStruct { foo: 1, bar: 2 });
+ $0if let Ok(MyStruct { foo, bar: 12 }) = bar {
+ ()
+ } else {
+ ()
+ }
+}
+"#,
+ r#"
+struct MyStruct {
+ foo: i32,
+ bar: i32,
+}
+
+fn foo(x: Result<MyStruct, ()>) {
+ let bar: Result<MyStruct, ()> = Ok(MyStruct { foo: 1, bar: 2 });
+ match bar {
+ Ok(MyStruct { foo, bar: 12 }) => (),
+ _ => (),
+ }
+}
+"#,
+ );
+
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+//- minicore: result
+struct MyStruct {
+ foo: i32,
+ bar: i32,
+}
+
+fn foo(x: Result<MyStruct, ()>) {
+ let bar: Result<MyStruct, ()> = Ok(MyStruct { foo: 1, bar: 2 });
+ $0if let Ok(MyStruct { foo, .. }) = bar {
+ ()
+ } else {
+ ()
+ }
+}
+"#,
+ r#"
+struct MyStruct {
+ foo: i32,
+ bar: i32,
+}
+
+fn foo(x: Result<MyStruct, ()>) {
+ let bar: Result<MyStruct, ()> = Ok(MyStruct { foo: 1, bar: 2 });
+ match bar {
+ Ok(MyStruct { foo, .. }) => (),
+ Err(_) => (),
+ }
+}
+"#,
+ );
+
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+//- minicore: result
+enum MyEnum {
+ Foo(i32, i32),
+ Bar { a: i32, b: i32 },
+}
+
+fn foo(x: Result<MyEnum, ()>) {
+ let bar: Result<MyEnum, ()> = Ok(MyEnum::Foo(1, 2));
+ $0if let Ok(MyEnum::Bar { a, b }) = bar {
+ ()
+ } else {
+ ()
+ }
+}
+"#,
+ r#"
+enum MyEnum {
+ Foo(i32, i32),
+ Bar { a: i32, b: i32 },
+}
+
+fn foo(x: Result<MyEnum, ()>) {
+ let bar: Result<MyEnum, ()> = Ok(MyEnum::Foo(1, 2));
+ match bar {
+ Ok(MyEnum::Bar { a, b }) => (),
+ _ => (),
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn test_if_let_with_match_nested_ident() {
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+//- minicore: result
+fn foo(x: Result<i32, ()>) {
+ let bar: Result<i32, ()> = Ok(1);
+ $0if let Ok(a @ 1..2) = bar {
+ ()
+ } else {
+ ()
+ }
+}
+"#,
+ r#"
+fn foo(x: Result<i32, ()>) {
+ let bar: Result<i32, ()> = Ok(1);
+ match bar {
+ Ok(a @ 1..2) => (),
+ _ => (),
+ }
+}
+"#,
+ );
+
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+//- minicore: result
+fn foo(x: Result<i32, ()>) {
+ let bar: Result<i32, ()> = Ok(1);
+ $0if let Ok(a) = bar {
+ ()
+ } else {
+ ()
+ }
+}
+"#,
+ r#"
+fn foo(x: Result<i32, ()>) {
+ let bar: Result<i32, ()> = Ok(1);
+ match bar {
+ Ok(a) => (),
+ Err(_) => (),
+ }
+}
+"#,
+ );
+
+ check_assist(
+ replace_if_let_with_match,
+ r#"
+//- minicore: result
+fn foo(x: Result<i32, ()>) {
+ let bar: Result<i32, ()> = Ok(1);
+ $0if let Ok(a @ b @ c @ d) = bar {
+ ()
+ } else {
+ ()
+ }
+}
+"#,
+ r#"
+fn foo(x: Result<i32, ()>) {
+ let bar: Result<i32, ()> = Ok(1);
+ match bar {
+ Ok(a @ b @ c @ d) => (),
+ Err(_) => (),
+ }
+}
+"#,
+ );
}
#[test]