Auto merge of #14037 - Veykril:if-let-match, r=Veykril

Handle boolean scrutinees in match <-> if let replacement assists better
This commit is contained in:
bors 2023-01-27 11:35:33 +00:00
commit 2935a89f3f

View File

@ -13,7 +13,7 @@
edit::{AstNodeEdit, IndentLevel}, edit::{AstNodeEdit, IndentLevel},
make, HasName, make, HasName,
}, },
AstNode, TextRange, AstNode, TextRange, T,
}; };
use crate::{ use crate::{
@ -96,8 +96,9 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext<'
cond_bodies.push((cond, body)); cond_bodies.push((cond, body));
} }
if !pat_seen { if !pat_seen && cond_bodies.len() != 1 {
// Don't offer turning an if (chain) without patterns into a match // Don't offer turning an if (chain) without patterns into a match,
// unless its a simple `if cond { .. } (else { .. })`
return None; return None;
} }
@ -114,6 +115,11 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext<'
Either::Left(pat) => { Either::Left(pat) => {
make::match_arm(iter::once(pat), None, unwrap_trivial_block(body)) make::match_arm(iter::once(pat), None, unwrap_trivial_block(body))
} }
Either::Right(_) if !pat_seen => make::match_arm(
iter::once(make::literal_pat("true").into()),
None,
unwrap_trivial_block(body),
),
Either::Right(expr) => make::match_arm( Either::Right(expr) => make::match_arm(
iter::once(make::wildcard_pat().into()), iter::once(make::wildcard_pat().into()),
Some(expr), Some(expr),
@ -144,17 +150,15 @@ fn make_else_arm(
else_block: Option<ast::BlockExpr>, else_block: Option<ast::BlockExpr>,
conditionals: &[(Either<ast::Pat, ast::Expr>, ast::BlockExpr)], conditionals: &[(Either<ast::Pat, ast::Expr>, ast::BlockExpr)],
) -> ast::MatchArm { ) -> ast::MatchArm {
if let Some(else_block) = else_block { let (pattern, expr) = if let Some(else_block) = else_block {
let pattern = if let [(Either::Left(pat), _)] = conditionals { let pattern = match conditionals {
ctx.sema [(Either::Right(_), _)] => make::literal_pat("false").into(),
[(Either::Left(pat), _)] => match ctx
.sema
.type_of_pat(pat) .type_of_pat(pat)
.and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty.adjusted())) .and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty.adjusted()))
.zip(Some(pat)) {
} else { Some(it) => {
None
};
let pattern = match pattern {
Some((it, pat)) => {
if does_pat_match_variant(pat, &it.sad_pattern()) { if does_pat_match_variant(pat, &it.sad_pattern()) {
it.happy_pattern_wildcard() it.happy_pattern_wildcard()
} else if does_nested_pattern(pat) { } else if does_nested_pattern(pat) {
@ -164,11 +168,18 @@ fn make_else_arm(
} }
} }
None => make::wildcard_pat().into(), None => make::wildcard_pat().into(),
},
_ => make::wildcard_pat().into(),
}; };
make::match_arm(iter::once(pattern), None, unwrap_trivial_block(else_block)) (pattern, unwrap_trivial_block(else_block))
} else { } else {
make::match_arm(iter::once(make::wildcard_pat().into()), None, make::expr_unit()) let pattern = match conditionals {
} [(Either::Right(_), _)] => make::literal_pat("false").into(),
_ => make::wildcard_pat().into(),
};
(pattern, make::expr_unit())
};
make::match_arm(iter::once(pattern), None, expr)
} }
// Assist: replace_match_with_if_let // Assist: replace_match_with_if_let
@ -231,7 +242,19 @@ fn make_block_expr(expr: ast::Expr) -> ast::BlockExpr {
} }
} }
let condition = make::expr_let(if_let_pat, scrutinee); let condition = match if_let_pat {
ast::Pat::LiteralPat(p)
if p.literal().map_or(false, |it| it.token().kind() == T![true]) =>
{
scrutinee
}
ast::Pat::LiteralPat(p)
if p.literal().map_or(false, |it| it.token().kind() == T![false]) =>
{
make::expr_prefix(T![!], scrutinee)
}
_ => make::expr_let(if_let_pat, scrutinee).into(),
};
let then_block = make_block_expr(then_expr.reset_indent()); let then_block = make_block_expr(then_expr.reset_indent());
let else_expr = if is_empty_expr(&else_expr) { None } else { Some(else_expr) }; let else_expr = if is_empty_expr(&else_expr) { None } else { Some(else_expr) };
let if_let_expr = make::expr_if( let if_let_expr = make::expr_if(
@ -327,6 +350,58 @@ fn main() {
) )
} }
#[test]
fn test_if_with_match_no_else() {
check_assist(
replace_if_let_with_match,
r#"
pub fn foo(foo: bool) {
if foo$0 {
self.foo();
}
}
"#,
r#"
pub fn foo(foo: bool) {
match foo {
true => {
self.foo();
}
false => (),
}
}
"#,
)
}
#[test]
fn test_if_with_match_with_else() {
check_assist(
replace_if_let_with_match,
r#"
pub fn foo(foo: bool) {
if foo$0 {
self.foo();
} else {
self.bar();
}
}
"#,
r#"
pub fn foo(foo: bool) {
match foo {
true => {
self.foo();
}
false => {
self.bar();
}
}
}
"#,
)
}
#[test] #[test]
fn test_if_let_with_match_no_else() { fn test_if_let_with_match_no_else() {
check_assist( check_assist(
@ -993,6 +1068,66 @@ fn main() {
code() code()
} }
} }
"#,
)
}
#[test]
fn test_replace_match_with_if_bool() {
check_assist(
replace_match_with_if_let,
r#"
fn main() {
match$0 b {
true => (),
_ => code(),
}
}
"#,
r#"
fn main() {
if b {
()
} else {
code()
}
}
"#,
);
check_assist(
replace_match_with_if_let,
r#"
fn main() {
match$0 b {
false => code(),
true => (),
}
}
"#,
r#"
fn main() {
if !b {
code()
}
}
"#,
);
check_assist(
replace_match_with_if_let,
r#"
fn main() {
match$0 b {
false => (),
true => code(),
}
}
"#,
r#"
fn main() {
if b {
code()
}
}
"#, "#,
) )
} }