More targeted parentheses suggestion for match statement intended as expression

```
error[E0308]: mismatched types
  --> $DIR/expr-as-stmt.rs:69:5
   |
LL |     match () { () => 1 } + match () { () => 1 }
   |     ^^^^^^^^^^^^^^^^^^^^ expected `()`, found integer
   |
help: parentheses are required to parse this as an expression
   |
LL |     (match () { () => 1 }) + match () { () => 1 }
   |     +                    +
```
This commit is contained in:
Esteban Küber
2025-08-31 01:43:57 +00:00
parent a7e32a5319
commit f5b5e67f0f
5 changed files with 116 additions and 26 deletions
@@ -1913,17 +1913,37 @@ fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>) {
// Check with expected type of `()`.
self.check_expr_has_type_or_error(expr, self.tcx.types.unit, |err| {
if expr.can_have_side_effects() {
self.suggest_semicolon_at_end(expr.span, err);
if let hir::ExprKind::Match(..) = expr.kind {
let hir_id = stmt.hir_id;
if let hir::ExprKind::Match(..) = expr.kind
&& let hir::Node::Block(b) = self.tcx.parent_hir_node(hir_id)
&& let mut stmts = b.stmts.iter().skip_while(|s| s.hir_id != hir_id)
&& let Some(_) = stmts.next() // The statement from the `match`
&& let Some(next) = match (stmts.next(), b.expr) {
(Some(next), _) => match next.kind {
hir::StmtKind::Expr(next) | hir::StmtKind::Semi(next) => Some(next),
_ => None,
},
(None, Some(next)) => Some(next),
_ => None,
}
&& let hir::ExprKind::AddrOf(..)
| hir::ExprKind::Unary(..)
| hir::ExprKind::Err(_) = next.kind
{
// We have something like `match () { _ => true } && true`. Suggest
// wrapping in parentheses. We find the statement or expression
// following the `match` (`&& true`) and see if it is something that
// can reasonably be interpreted as a binop following an expression.
err.multipart_suggestion(
"alternatively, parentheses are required to parse this as an \
expression",
"parentheses are required to parse this as an expression",
vec![
(expr.span.shrink_to_lo(), "(".to_string()),
(expr.span.shrink_to_hi(), ")".to_string()),
],
Applicability::MaybeIncorrect,
Applicability::MachineApplicable,
);
} else {
self.suggest_semicolon_at_end(expr.span, err);
}
}
});
+10 -1
View File
@@ -66,7 +66,7 @@ fn asteroids() -> impl FnOnce() -> bool {
// https://github.com/rust-lang/rust/issues/105179
fn r#match() -> i32 {
(match () { () => 1 }) + match () { () => 1 } //~ ERROR expected expression, found `+`
((match () { () => 1 })) + match () { () => 1 } //~ ERROR expected expression, found `+`
//~^ ERROR mismatched types
}
@@ -76,4 +76,13 @@ fn r#unsafe() -> i32 {
//~^ ERROR mismatched types
}
// https://github.com/rust-lang/rust/issues/88727
fn matches() -> bool {
(match () { _ => true }) && match () { _ => true }; //~ ERROR mismatched types
(match () { _ => true }) && match () { _ => true }; //~ ERROR mismatched types
//~^ ERROR expected `;`, found keyword `match`
(match () { _ => true }) && true; //~ ERROR mismatched types
((match () { _ => true })) && true //~ ERROR mismatched types
//~^ ERROR mismatched types
}
fn main() {}
+9
View File
@@ -76,4 +76,13 @@ fn r#unsafe() -> i32 {
//~^ ERROR mismatched types
}
// https://github.com/rust-lang/rust/issues/88727
fn matches() -> bool {
match () { _ => true } && match () { _ => true }; //~ ERROR mismatched types
match () { _ => true } && match () { _ => true } //~ ERROR mismatched types
//~^ ERROR expected `;`, found keyword `match`
match () { _ => true } && true; //~ ERROR mismatched types
match () { _ => true } && true //~ ERROR mismatched types
//~^ ERROR mismatched types
}
fn main() {}
+69 -6
View File
@@ -77,6 +77,15 @@ help: parentheses are required to parse this as an expression
LL | (unsafe { 1 }) + unsafe { 1 }
| + +
error: expected `;`, found keyword `match`
--> $DIR/expr-as-stmt.rs:82:53
|
LL | match () { _ => true } && match () { _ => true }
| ^ help: add `;` here
LL |
LL | match () { _ => true } && true;
| ----- unexpected token
error[E0308]: mismatched types
--> $DIR/expr-as-stmt.rs:64:7
|
@@ -229,11 +238,7 @@ error[E0308]: mismatched types
LL | match () { () => 1 } + match () { () => 1 }
| ^^^^^^^^^^^^^^^^^^^^ expected `()`, found integer
|
help: consider using a semicolon here
|
LL | match () { () => 1 }; + match () { () => 1 }
| +
help: alternatively, parentheses are required to parse this as an expression
help: parentheses are required to parse this as an expression
|
LL | (match () { () => 1 }) + match () { () => 1 }
| + +
@@ -249,7 +254,65 @@ help: you might have meant to return this value
LL | unsafe { return 1; } + unsafe { 1 }
| ++++++ +
error: aborting due to 22 previous errors
error[E0308]: mismatched types
--> $DIR/expr-as-stmt.rs:81:5
|
LL | match () { _ => true } && match () { _ => true };
| ^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `bool`
|
help: parentheses are required to parse this as an expression
|
LL | (match () { _ => true }) && match () { _ => true };
| + +
error[E0308]: mismatched types
--> $DIR/expr-as-stmt.rs:82:5
|
LL | match () { _ => true } && match () { _ => true }
| ^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `bool`
|
help: parentheses are required to parse this as an expression
|
LL | (match () { _ => true }) && match () { _ => true }
| + +
error[E0308]: mismatched types
--> $DIR/expr-as-stmt.rs:84:5
|
LL | match () { _ => true } && true;
| ^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `bool`
|
help: parentheses are required to parse this as an expression
|
LL | (match () { _ => true }) && true;
| + +
error[E0308]: mismatched types
--> $DIR/expr-as-stmt.rs:85:5
|
LL | match () { _ => true } && true
| ^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `bool`
|
help: parentheses are required to parse this as an expression
|
LL | (match () { _ => true }) && true
| + +
error[E0308]: mismatched types
--> $DIR/expr-as-stmt.rs:85:28
|
LL | fn matches() -> bool {
| ---- expected `bool` because of return type
...
LL | match () { _ => true } && true
| ^^^^^^^ expected `bool`, found `&&bool`
|
help: parentheses are required to parse this as an expression
|
LL | (match () { _ => true }) && true
| + +
error: aborting due to 28 previous errors
Some errors have detailed explanations: E0308, E0600, E0614.
For more information about an error, try `rustc --explain E0308`.
+3 -14
View File
@@ -28,20 +28,9 @@ LL | | 4 => 1,
LL | | 3 => 2,
LL | | _ => 2
LL | | }
| |_____^ expected `()`, found integer
|
help: consider using a semicolon here
|
LL | };
| +
help: alternatively, parentheses are required to parse this as an expression
|
LL ~ (match 3 {
LL | 4 => 1,
LL | 3 => 2,
LL | _ => 2
LL ~ })
|
| | ^- help: consider using a semicolon here
| |_____|
| expected `()`, found integer
error: aborting due to 2 previous errors