Skip to content

Commit 7f0acb3

Browse files
committed
fix: wrap match scrutinee in parens when needed in replace_if_let_with_match
`if (return) {}` caused a panic in `replace_if_let_with_match`: `let_and_guard` recursed through the `ParenExpr`, producing a bare `return` as the scrutinee. `make::expr_match` formatted `match return { ... }`, which the parser reinterpreted as `match (return { ... })`, consuming the arm list as the return value. The resulting match expr had no `MatchArmList`, so the `unwrap()` in `SyntaxFactory::expr_match` panicked. Mirror the fix pattern from #22067: build a fake `match () { }` and ask whether the scrutinee needs parens in that position via `needs_parens_in_place_of`. Wrap when required. fixes #22072
1 parent 26d7ba3 commit 7f0acb3

1 file changed

Lines changed: 36 additions & 0 deletions

File tree

crates/ide-assists/src/handlers/replace_if_let_with_match.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,11 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext<'
132132
};
133133
let arms = cond_bodies.into_iter().map(make_match_arm).chain([else_arm]);
134134
let expr = scrutinee_to_be_expr.reset_indent();
135+
let expr = if match_scrutinee_needs_paren(&expr) {
136+
make.expr_paren(expr).into()
137+
} else {
138+
expr
139+
};
135140
let match_expr = make.expr_match(expr, make.match_arm_list(arms)).indent(indent);
136141
match_expr.into()
137142
};
@@ -419,6 +424,17 @@ fn let_and_guard(cond: &ast::Expr) -> (Option<ast::LetExpr>, Option<ast::Expr>)
419424
}
420425
}
421426

427+
fn match_scrutinee_needs_paren(expr: &ast::Expr) -> bool {
428+
let make = SyntaxFactory::without_mappings();
429+
let fake_scrutinee = make.expr_unit();
430+
let fake_match = make.expr_match(fake_scrutinee, make.match_arm_list(std::iter::empty()));
431+
let Some(fake_expr) = fake_match.expr() else {
432+
stdx::never!();
433+
return false;
434+
};
435+
expr.needs_parens_in_place_of(fake_match.syntax(), fake_expr.syntax())
436+
}
437+
422438
fn and_bin_expr_left(expr: &ast::BinExpr) -> ast::BinExpr {
423439
if expr.op_kind() == Some(ast::BinaryOp::LogicOp(ast::LogicOp::And))
424440
&& let Some(ast::Expr::BinExpr(left)) = expr.lhs()
@@ -447,6 +463,26 @@ fn main() {
447463
)
448464
}
449465

466+
#[test]
467+
fn test_if_with_match_paren_jump_scrutinee() {
468+
check_assist(
469+
replace_if_let_with_match,
470+
r#"
471+
fn f() {
472+
if $0(return) {}
473+
}
474+
"#,
475+
r#"
476+
fn f() {
477+
match (return) {
478+
true => {}
479+
false => (),
480+
}
481+
}
482+
"#,
483+
)
484+
}
485+
450486
#[test]
451487
fn test_if_with_match_no_else() {
452488
check_assist(

0 commit comments

Comments
 (0)