about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs30
-rw-r--r--tests/ui/parser/expr-as-stmt.fixed11
-rw-r--r--tests/ui/parser/expr-as-stmt.rs9
-rw-r--r--tests/ui/parser/expr-as-stmt.stderr75
-rw-r--r--tests/ui/suggestions/match-needing-semi.stderr17
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