diff options
| -rw-r--r-- | compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 30 | ||||
| -rw-r--r-- | tests/ui/parser/expr-as-stmt.fixed | 11 | ||||
| -rw-r--r-- | tests/ui/parser/expr-as-stmt.rs | 9 | ||||
| -rw-r--r-- | tests/ui/parser/expr-as-stmt.stderr | 75 | ||||
| -rw-r--r-- | tests/ui/suggestions/match-needing-semi.stderr | 17 |
5 files changed, 116 insertions, 26 deletions
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index e70e444a53d..33dc56d49b4 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1913,17 +1913,37 @@ impl<'a, 'tcx> FnCtxt<'a, '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); } } }); diff --git a/tests/ui/parser/expr-as-stmt.fixed b/tests/ui/parser/expr-as-stmt.fixed index 0a4d62a4a0c..bfae55047ed 100644 --- a/tests/ui/parser/expr-as-stmt.fixed +++ b/tests/ui/parser/expr-as-stmt.fixed @@ -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() {} diff --git a/tests/ui/parser/expr-as-stmt.rs b/tests/ui/parser/expr-as-stmt.rs index 99c85e65baa..94917432cb0 100644 --- a/tests/ui/parser/expr-as-stmt.rs +++ b/tests/ui/parser/expr-as-stmt.rs @@ -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() {} diff --git a/tests/ui/parser/expr-as-stmt.stderr b/tests/ui/parser/expr-as-stmt.stderr index 562162ef394..4681129baba 100644 --- a/tests/ui/parser/expr-as-stmt.stderr +++ b/tests/ui/parser/expr-as-stmt.stderr @@ -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`. diff --git a/tests/ui/suggestions/match-needing-semi.stderr b/tests/ui/suggestions/match-needing-semi.stderr index 8f74997fdbe..b5f01d7038c 100644 --- a/tests/ui/suggestions/match-needing-semi.stderr +++ b/tests/ui/suggestions/match-needing-semi.stderr @@ -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 |
