use syntax::{
- ast::{
- edit::AstNodeEdit, make, AstNode, BlockExpr, Condition, ElseBranch, Expr, IfExpr, MatchArm,
- },
+ ast::{edit::AstNodeEdit, make, AstNode, BlockExpr, ElseBranch, Expr, IfExpr, MatchArm, Pat},
SyntaxKind::WHITESPACE,
};
}
let space_before_guard = guard.syntax().prev_sibling_or_token();
- // FIXME: support `if let` guards too
- if guard.let_token().is_some() {
- return None;
- }
- let guard_condition = guard.expr()?;
+ let guard_condition = guard.condition()?;
let arm_expr = match_arm.expr()?;
- let if_expr = make::expr_if(
- make::condition(guard_condition, None),
- make::block_expr(None, Some(arm_expr.clone())),
- None,
- )
- .indent(arm_expr.indent_level());
+ let if_expr =
+ make::expr_if(guard_condition, make::block_expr(None, Some(arm_expr.clone())), None)
+ .indent(arm_expr.indent_level());
let target = guard.syntax().text_range();
acc.add(
}
}
}
- match tail {
- Some(Tail::IfLet(e)) => {
- cov_mark::hit!(move_guard_ifelse_iflet_tail);
- let guard = format!("\n{}{} => ", spaces, match_pat);
- // Put the if-let expression in a block
- let iflet_expr: Expr = e.reset_indent().indent(1.into()).into();
- let iflet_block =
- make::block_expr(std::iter::empty(), Some(iflet_expr)).indent(indent_level);
- edit.insert(then_arm_end, guard);
- edit.insert(then_arm_end, iflet_block.syntax().text());
- }
- Some(Tail::Else(e)) => {
- cov_mark::hit!(move_guard_ifelse_else_tail);
- let guard = format!("\n{}{} => ", spaces, match_pat);
- edit.insert(then_arm_end, guard);
- let only_expr = e.statements().next().is_none();
- match &e.tail_expr() {
- Some(expr) if only_expr => {
- cov_mark::hit!(move_guard_ifelse_expr_only);
- edit.insert(then_arm_end, expr.syntax().text());
- edit.insert(then_arm_end, ",");
- }
- _ => {
- let to_insert = e.dedent(dedent.into()).syntax().text();
- edit.insert(then_arm_end, to_insert)
- }
+ if let Some(e) = tail {
+ cov_mark::hit!(move_guard_ifelse_else_tail);
+ let guard = format!("\n{}{} => ", spaces, match_pat);
+ edit.insert(then_arm_end, guard);
+ let only_expr = e.statements().next().is_none();
+ match &e.tail_expr() {
+ Some(expr) if only_expr => {
+ cov_mark::hit!(move_guard_ifelse_expr_only);
+ edit.insert(then_arm_end, expr.syntax().text());
+ edit.insert(then_arm_end, ",");
+ }
+ _ => {
+ let to_insert = e.dedent(dedent.into()).syntax().text();
+ edit.insert(then_arm_end, to_insert)
}
}
- _ => {
- cov_mark::hit!(move_guard_ifelse_notail);
+ } else {
+ // There's no else branch. Add a pattern without guard, unless the following match
+ // arm is `_ => ...`
+ cov_mark::hit!(move_guard_ifelse_notail);
+ match match_arm.syntax().next_sibling().and_then(MatchArm::cast) {
+ Some(next_arm)
+ if matches!(next_arm.pat(), Some(Pat::WildcardPat(_)))
+ && next_arm.guard().is_none() =>
+ {
+ cov_mark::hit!(move_guard_ifelse_has_wildcard);
+ }
+ _ => edit.insert(then_arm_end, format!("\n{}{} => {{}}", spaces, match_pat)),
}
}
},
)
}
-#[derive(Debug)]
-enum Tail {
- Else(BlockExpr),
- IfLet(IfExpr),
-}
-
-// Parses an if-else-if chain to get the conditons and the then branches until we encounter an else
-// branch, an if-let branch or the end.
-fn parse_if_chain(if_expr: IfExpr) -> Option<(Vec<(Condition, BlockExpr)>, Option<Tail>)> {
+// Parses an if-else-if chain to get the conditions and the then branches until we encounter an else
+// branch or the end.
+fn parse_if_chain(if_expr: IfExpr) -> Option<(Vec<(Expr, BlockExpr)>, Option<BlockExpr>)> {
let mut conds_blocks = Vec::new();
let mut curr_if = if_expr;
- let mut applicable = false;
- let tail: Option<Tail> = loop {
+ let tail = loop {
let cond = curr_if.condition()?;
- if cond.is_pattern_cond() {
- break Some(Tail::IfLet(curr_if));
- }
conds_blocks.push((cond, curr_if.then_branch()?));
- applicable = true;
match curr_if.else_branch() {
Some(ElseBranch::IfExpr(e)) => {
curr_if = e;
}
Some(ElseBranch::Block(b)) => {
- break Some(Tail::Else(b));
+ break Some(b);
}
None => break None,
}
};
- if !applicable {
- // The first if branch is an if-let branch
- return None;
- }
Some((conds_blocks, tail))
}
);
}
+ #[test]
+ fn move_let_guard_to_arm_body_works() {
+ check_assist(
+ move_guard_to_arm_body,
+ r#"
+fn main() {
+ match 92 {
+ x $0if (let 1 = x) => false,
+ _ => true
+ }
+}
+"#,
+ r#"
+fn main() {
+ match 92 {
+ x => if (let 1 = x) {
+ false
+ },
+ _ => true
+ }
+}
+"#,
+ );
+ }
+
#[test]
fn move_guard_to_arm_body_works_complex_match() {
check_assist(
#[test]
fn move_arm_cond_in_block_to_match_guard_works() {
+ cov_mark::check!(move_guard_ifelse_has_wildcard);
check_assist(
move_arm_cond_to_match_guard,
r#"
);
}
+ #[test]
+ fn move_arm_cond_in_block_to_match_guard_no_wildcard_works() {
+ cov_mark::check_count!(move_guard_ifelse_has_wildcard, 0);
+ check_assist(
+ move_arm_cond_to_match_guard,
+ r#"
+fn main() {
+ match 92 {
+ x => {
+ $0if x > 10 {
+ false
+ }
+ }
+ }
+}
+"#,
+ r#"
+fn main() {
+ match 92 {
+ x if x > 10 => false,
+ x => {}
+ }
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn move_arm_cond_in_block_to_match_guard_wildcard_guard_works() {
+ cov_mark::check_count!(move_guard_ifelse_has_wildcard, 0);
+ check_assist(
+ move_arm_cond_to_match_guard,
+ r#"
+fn main() {
+ match 92 {
+ x => {
+ $0if x > 10 {
+ false
+ }
+ }
+ _ if x > 10 => true,
+ }
+}
+"#,
+ r#"
+fn main() {
+ match 92 {
+ x if x > 10 => false,
+ x => {}
+ _ if x > 10 => true,
+ }
+}
+"#,
+ );
+ }
+
#[test]
fn move_arm_cond_in_block_to_match_guard_add_comma_works() {
check_assist(
}
#[test]
- fn move_arm_cond_to_match_guard_if_let_not_works() {
- check_assist_not_applicable(
+ fn move_arm_cond_to_match_guard_if_let_works() {
+ check_assist(
move_arm_cond_to_match_guard,
r#"
fn main() {
match 92 {
- x => if let 62 = x { $0false },
+ x => if let 62 = x && true { $0false },
+ _ => true
+ }
+}
+"#,
+ r#"
+fn main() {
+ match 92 {
+ x if let 62 = x && true => false,
_ => true
}
}
#[test]
fn move_arm_cond_to_match_guard_elseif_iflet() {
- cov_mark::check!(move_guard_ifelse_iflet_tail);
check_assist(
move_arm_cond_to_match_guard,
r#"
4
},
}
-}
-"#,
+}"#,
r#"
fn main() {
match 92 {
3 => 0,
x if x > 10 => 1,
x if x > 5 => 2,
- x => {
- if let 4 = 4 {
- 42;
- 3
- } else {
- 4
- }
+ x if let 4 = 4 => {
+ 42;
+ 3
}
+ x => 4,
}
-}
-"#,
- )
+}"#,
+ );
}
#[test]
42;
3
}
+ x => {}
}
}
"#,