Unnamed repository; edit this file 'description' to name the repository.
Stop inserting semicolon when extracting match arm
# Overview
Extracting a match arm value that has type unit into a function, when a
comma already follows the match arm value, results in an invalid (syntax
error) semicolon added between the newly generated function's generated
call and the comma.
# Example
Running this extraction
```rust
fn main() {
match () {
_ => $0()$0,
};
}
```
would lead to
```rust
fn main() {
match () {
_ => fun_name();,
};
}
fn fun_name() {
}
```
# Issue / Fix details
This happens because when there is no comma, rust-analyzer would simply
add the comma and wouldn't even try to evaluate whether it needs to add
a semicolon. But when the comma is there, it proceeds to evaluate
whether it needs to add a semicolon and it looks like the evaluation
logic erroneously ignores the possibility that we're in a match arm.
IIUC it never makes sense to add a semicolon when we're extracting from
a match arm value, so I've adjusted the logic to always decide against
adding a semicolon when we're in a match arm
| -rw-r--r-- | crates/ide-assists/src/handlers/extract_function.rs | 36 |
1 files changed, 30 insertions, 6 deletions
diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs index 2a67909e63..e9db38aca0 100644 --- a/crates/ide-assists/src/handlers/extract_function.rs +++ b/crates/ide-assists/src/handlers/extract_function.rs @@ -1360,14 +1360,15 @@ fn make_call(ctx: &AssistContext<'_>, fun: &Function, indent: IndentLevel) -> St } format_to!(buf, "{expr}"); - let insert_comma = fun - .body - .parent() - .and_then(ast::MatchArm::cast) - .map_or(false, |it| it.comma_token().is_none()); + let parent_match_arm = fun.body.parent().and_then(ast::MatchArm::cast); + let insert_comma = parent_match_arm.as_ref().is_some_and(|it| it.comma_token().is_none()); + if insert_comma { buf.push(','); - } else if fun.ret_ty.is_unit() && (!fun.outliving_locals.is_empty() || !expr.is_block_like()) { + } else if parent_match_arm.is_none() + && fun.ret_ty.is_unit() + && (!fun.outliving_locals.is_empty() || !expr.is_block_like()) + { buf.push(';'); } buf @@ -4611,6 +4612,29 @@ fn $0fun_name() -> i32 { } "#, ); + + // Makes sure no semicolon is added for unit-valued match arms + check_assist( + extract_function, + r#" +fn main() { + match () { + _ => $0()$0, + } +} +"#, + r#" +fn main() { + match () { + _ => fun_name(), + } +} + +fn $0fun_name() { + () +} +"#, + ) } #[test] |