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
This commit is contained in:
Omer Tuchfeld 2023-07-08 13:48:04 +02:00
parent db0add1ce9
commit 9200d27a26

View File

@ -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]