Skip to content

Commit f5b5e67

Browse files
committed
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 } | + + ```
1 parent a7e32a5 commit f5b5e67

File tree

5 files changed

+116
-26
lines changed

5 files changed

+116
-26
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1913,17 +1913,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
19131913
// Check with expected type of `()`.
19141914
self.check_expr_has_type_or_error(expr, self.tcx.types.unit, |err| {
19151915
if expr.can_have_side_effects() {
1916-
self.suggest_semicolon_at_end(expr.span, err);
1917-
if let hir::ExprKind::Match(..) = expr.kind {
1916+
let hir_id = stmt.hir_id;
1917+
if let hir::ExprKind::Match(..) = expr.kind
1918+
&& let hir::Node::Block(b) = self.tcx.parent_hir_node(hir_id)
1919+
&& let mut stmts = b.stmts.iter().skip_while(|s| s.hir_id != hir_id)
1920+
&& let Some(_) = stmts.next() // The statement from the `match`
1921+
&& let Some(next) = match (stmts.next(), b.expr) {
1922+
(Some(next), _) => match next.kind {
1923+
hir::StmtKind::Expr(next) | hir::StmtKind::Semi(next) => Some(next),
1924+
_ => None,
1925+
},
1926+
(None, Some(next)) => Some(next),
1927+
_ => None,
1928+
}
1929+
&& let hir::ExprKind::AddrOf(..)
1930+
| hir::ExprKind::Unary(..)
1931+
| hir::ExprKind::Err(_) = next.kind
1932+
{
1933+
// We have something like `match () { _ => true } && true`. Suggest
1934+
// wrapping in parentheses. We find the statement or expression
1935+
// following the `match` (`&& true`) and see if it is something that
1936+
// can reasonably be interpreted as a binop following an expression.
19181937
err.multipart_suggestion(
1919-
"alternatively, parentheses are required to parse this as an \
1920-
expression",
1938+
"parentheses are required to parse this as an expression",
19211939
vec![
19221940
(expr.span.shrink_to_lo(), "(".to_string()),
19231941
(expr.span.shrink_to_hi(), ")".to_string()),
19241942
],
1925-
Applicability::MaybeIncorrect,
1943+
Applicability::MachineApplicable,
19261944
);
1945+
} else {
1946+
self.suggest_semicolon_at_end(expr.span, err);
19271947
}
19281948
}
19291949
});

tests/ui/parser/expr-as-stmt.fixed

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ fn asteroids() -> impl FnOnce() -> bool {
6666

6767
// https://github.com/rust-lang/rust/issues/105179
6868
fn r#match() -> i32 {
69-
(match () { () => 1 }) + match () { () => 1 } //~ ERROR expected expression, found `+`
69+
((match () { () => 1 })) + match () { () => 1 } //~ ERROR expected expression, found `+`
7070
//~^ ERROR mismatched types
7171
}
7272

@@ -76,4 +76,13 @@ fn r#unsafe() -> i32 {
7676
//~^ ERROR mismatched types
7777
}
7878

79+
// https://github.com/rust-lang/rust/issues/88727
80+
fn matches() -> bool {
81+
(match () { _ => true }) && match () { _ => true }; //~ ERROR mismatched types
82+
(match () { _ => true }) && match () { _ => true }; //~ ERROR mismatched types
83+
//~^ ERROR expected `;`, found keyword `match`
84+
(match () { _ => true }) && true; //~ ERROR mismatched types
85+
((match () { _ => true })) && true //~ ERROR mismatched types
86+
//~^ ERROR mismatched types
87+
}
7988
fn main() {}

tests/ui/parser/expr-as-stmt.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,13 @@ fn r#unsafe() -> i32 {
7676
//~^ ERROR mismatched types
7777
}
7878

79+
// https://github.com/rust-lang/rust/issues/88727
80+
fn matches() -> bool {
81+
match () { _ => true } && match () { _ => true }; //~ ERROR mismatched types
82+
match () { _ => true } && match () { _ => true } //~ ERROR mismatched types
83+
//~^ ERROR expected `;`, found keyword `match`
84+
match () { _ => true } && true; //~ ERROR mismatched types
85+
match () { _ => true } && true //~ ERROR mismatched types
86+
//~^ ERROR mismatched types
87+
}
7988
fn main() {}

tests/ui/parser/expr-as-stmt.stderr

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,15 @@ help: parentheses are required to parse this as an expression
7777
LL | (unsafe { 1 }) + unsafe { 1 }
7878
| + +
7979

80+
error: expected `;`, found keyword `match`
81+
--> $DIR/expr-as-stmt.rs:82:53
82+
|
83+
LL | match () { _ => true } && match () { _ => true }
84+
| ^ help: add `;` here
85+
LL |
86+
LL | match () { _ => true } && true;
87+
| ----- unexpected token
88+
8089
error[E0308]: mismatched types
8190
--> $DIR/expr-as-stmt.rs:64:7
8291
|
@@ -229,11 +238,7 @@ error[E0308]: mismatched types
229238
LL | match () { () => 1 } + match () { () => 1 }
230239
| ^^^^^^^^^^^^^^^^^^^^ expected `()`, found integer
231240
|
232-
help: consider using a semicolon here
233-
|
234-
LL | match () { () => 1 }; + match () { () => 1 }
235-
| +
236-
help: alternatively, parentheses are required to parse this as an expression
241+
help: parentheses are required to parse this as an expression
237242
|
238243
LL | (match () { () => 1 }) + match () { () => 1 }
239244
| + +
@@ -249,7 +254,65 @@ help: you might have meant to return this value
249254
LL | unsafe { return 1; } + unsafe { 1 }
250255
| ++++++ +
251256

252-
error: aborting due to 22 previous errors
257+
error[E0308]: mismatched types
258+
--> $DIR/expr-as-stmt.rs:81:5
259+
|
260+
LL | match () { _ => true } && match () { _ => true };
261+
| ^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `bool`
262+
|
263+
help: parentheses are required to parse this as an expression
264+
|
265+
LL | (match () { _ => true }) && match () { _ => true };
266+
| + +
267+
268+
error[E0308]: mismatched types
269+
--> $DIR/expr-as-stmt.rs:82:5
270+
|
271+
LL | match () { _ => true } && match () { _ => true }
272+
| ^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `bool`
273+
|
274+
help: parentheses are required to parse this as an expression
275+
|
276+
LL | (match () { _ => true }) && match () { _ => true }
277+
| + +
278+
279+
error[E0308]: mismatched types
280+
--> $DIR/expr-as-stmt.rs:84:5
281+
|
282+
LL | match () { _ => true } && true;
283+
| ^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `bool`
284+
|
285+
help: parentheses are required to parse this as an expression
286+
|
287+
LL | (match () { _ => true }) && true;
288+
| + +
289+
290+
error[E0308]: mismatched types
291+
--> $DIR/expr-as-stmt.rs:85:5
292+
|
293+
LL | match () { _ => true } && true
294+
| ^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `bool`
295+
|
296+
help: parentheses are required to parse this as an expression
297+
|
298+
LL | (match () { _ => true }) && true
299+
| + +
300+
301+
error[E0308]: mismatched types
302+
--> $DIR/expr-as-stmt.rs:85:28
303+
|
304+
LL | fn matches() -> bool {
305+
| ---- expected `bool` because of return type
306+
...
307+
LL | match () { _ => true } && true
308+
| ^^^^^^^ expected `bool`, found `&&bool`
309+
|
310+
help: parentheses are required to parse this as an expression
311+
|
312+
LL | (match () { _ => true }) && true
313+
| + +
314+
315+
error: aborting due to 28 previous errors
253316

254317
Some errors have detailed explanations: E0308, E0600, E0614.
255318
For more information about an error, try `rustc --explain E0308`.

tests/ui/suggestions/match-needing-semi.stderr

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,9 @@ LL | | 4 => 1,
2828
LL | | 3 => 2,
2929
LL | | _ => 2
3030
LL | | }
31-
| |_____^ expected `()`, found integer
32-
|
33-
help: consider using a semicolon here
34-
|
35-
LL | };
36-
| +
37-
help: alternatively, parentheses are required to parse this as an expression
38-
|
39-
LL ~ (match 3 {
40-
LL | 4 => 1,
41-
LL | 3 => 2,
42-
LL | _ => 2
43-
LL ~ })
44-
|
31+
| | ^- help: consider using a semicolon here
32+
| |_____|
33+
| expected `()`, found integer
4534

4635
error: aborting due to 2 previous errors
4736

0 commit comments

Comments
 (0)