about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs16
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs1
-rw-r--r--compiler/rustc_typeck/src/check/_match.rs1
-rw-r--r--src/test/ui/match/match-incompat-type-semi.rs10
-rw-r--r--src/test/ui/match/match-incompat-type-semi.stderr40
5 files changed, 53 insertions, 15 deletions
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 795c5a64d26..3a0ec6327c1 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -619,6 +619,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 scrut_hir_id,
                 opt_suggest_box_span,
                 arm_span,
+                scrut_span,
                 ..
             }) => match source {
                 hir::MatchSource::IfLetDesugar { .. } => {
@@ -664,18 +665,29 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                         Some(ty::error::ExpectedFound { expected, .. }) => expected,
                         _ => last_ty,
                     });
-                    let msg = "`match` arms have incompatible types";
-                    err.span_label(cause.span, msg);
+                    let source_map = self.tcx.sess.source_map();
+                    let mut any_multiline_arm = source_map.is_multiline(arm_span);
                     if prior_arms.len() <= 4 {
                         for sp in prior_arms {
+                            any_multiline_arm |= source_map.is_multiline(*sp);
                             err.span_label(*sp, format!("this is found to be of type `{}`", t));
                         }
                     } else if let Some(sp) = prior_arms.last() {
+                        any_multiline_arm |= source_map.is_multiline(*sp);
                         err.span_label(
                             *sp,
                             format!("this and all prior arms are found to be of type `{}`", t),
                         );
                     }
+                    let outer_error_span = if any_multiline_arm {
+                        // Cover just `match` and the scrutinee expression, not
+                        // the entire match body, to reduce diagram noise.
+                        cause.span.shrink_to_lo().to(scrut_span)
+                    } else {
+                        cause.span
+                    };
+                    let msg = "`match` arms have incompatible types";
+                    err.span_label(outer_error_span, msg);
                     if let Some(sp) = semi_span {
                         err.span_suggestion_short(
                             sp,
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 26962aa1083..bbc46b8d608 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -343,6 +343,7 @@ static_assert_size!(ObligationCauseCode<'_>, 32);
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
 pub struct MatchExpressionArmCause<'tcx> {
     pub arm_span: Span,
+    pub scrut_span: Span,
     pub semi_span: Option<Span>,
     pub source: hir::MatchSource,
     pub prior_arms: Vec<Span>,
diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs
index 7cb23dc0537..398e013e62f 100644
--- a/compiler/rustc_typeck/src/check/_match.rs
+++ b/compiler/rustc_typeck/src/check/_match.rs
@@ -201,6 +201,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         expr.span,
                         ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
                             arm_span,
+                            scrut_span: scrut.span,
                             semi_span,
                             source: match_src,
                             prior_arms: other_arms.clone(),
diff --git a/src/test/ui/match/match-incompat-type-semi.rs b/src/test/ui/match/match-incompat-type-semi.rs
index 9ab40fa3cce..37f6beabd33 100644
--- a/src/test/ui/match/match-incompat-type-semi.rs
+++ b/src/test/ui/match/match-incompat-type-semi.rs
@@ -39,4 +39,14 @@ fn main() {
         None => { //~ ERROR incompatible types
         },
     };
+
+    let _ = match Some(42) {
+        Some(x) => "rust-lang.org"
+            .chars()
+            .skip(1)
+            .chain(Some(x as u8 as char))
+            .take(10)
+            .any(char::is_alphanumeric),
+        None => {} //~ ERROR incompatible types
+    };
 }
diff --git a/src/test/ui/match/match-incompat-type-semi.stderr b/src/test/ui/match/match-incompat-type-semi.stderr
index 701f15fdc4b..008b1c1e93d 100644
--- a/src/test/ui/match/match-incompat-type-semi.stderr
+++ b/src/test/ui/match/match-incompat-type-semi.stderr
@@ -56,19 +56,33 @@ LL | |     };
 error[E0308]: `match` arms have incompatible types
   --> $DIR/match-incompat-type-semi.rs:39:17
    |
-LL |        let _ = match Some(42) {
-   |   _____________-
-LL |  |         Some(x) => {
-LL |  |             x
-   |  |             - this is found to be of type `{integer}`
-LL |  |         },
-LL |  |         None => {
-   |  |_________________^
-LL | ||         },
-   | ||_________^ expected integer, found `()`
-LL |  |     };
-   |  |_____- `match` arms have incompatible types
+LL |       let _ = match Some(42) {
+   |               -------------- `match` arms have incompatible types
+LL |           Some(x) => {
+LL |               x
+   |               - this is found to be of type `{integer}`
+LL |           },
+LL |           None => {
+   |  _________________^
+LL | |         },
+   | |_________^ expected integer, found `()`
+
+error[E0308]: `match` arms have incompatible types
+  --> $DIR/match-incompat-type-semi.rs:50:17
+   |
+LL |       let _ = match Some(42) {
+   |               -------------- `match` arms have incompatible types
+LL |           Some(x) => "rust-lang.org"
+   |  ____________________-
+LL | |             .chars()
+LL | |             .skip(1)
+LL | |             .chain(Some(x as u8 as char))
+LL | |             .take(10)
+LL | |             .any(char::is_alphanumeric),
+   | |_______________________________________- this is found to be of type `bool`
+LL |           None => {}
+   |                   ^^ expected `bool`, found `()`
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0308`.