From f82adf5bdba6e2a9fe4a42c9d260f20b60b33960 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 22 Oct 2020 16:08:26 -0700 Subject: [PATCH 1/2] Add test of incompatible match arm types with multiline arm --- src/test/ui/match/match-incompat-type-semi.rs | 10 ++++++++++ .../ui/match/match-incompat-type-semi.stderr | 20 ++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/test/ui/match/match-incompat-type-semi.rs b/src/test/ui/match/match-incompat-type-semi.rs index 9ab40fa3cce94..37f6beabd3302 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 701f15fdc4b60..1a2dbbcc29fb3 100644 --- a/src/test/ui/match/match-incompat-type-semi.stderr +++ b/src/test/ui/match/match-incompat-type-semi.stderr @@ -69,6 +69,24 @@ LL | || }, LL | | }; | |_____- `match` arms have incompatible types -error: aborting due to 4 previous errors +error[E0308]: `match` arms have incompatible types + --> $DIR/match-incompat-type-semi.rs:50:17 + | +LL | let _ = match Some(42) { + | _____________- +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 `()` +LL | | }; + | |_____- `match` arms have incompatible types + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0308`. From b0059500f6765612fbda6d33240116f7520d433a Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 22 Oct 2020 14:20:02 -0700 Subject: [PATCH 2/2] Reduce diagram mess in 'match arms have incompatible types' error --- .../src/infer/error_reporting/mod.rs | 16 ++++++- compiler/rustc_middle/src/traits/mod.rs | 1 + compiler/rustc_typeck/src/check/_match.rs | 1 + .../ui/match/match-incompat-type-semi.stderr | 48 +++++++++---------- 4 files changed, 38 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 795c5a64d26b7..3a0ec6327c186 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 26962aa108342..bbc46b8d60835 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, pub source: hir::MatchSource, pub prior_arms: Vec, diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs index 7cb23dc053795..398e013e62fb5 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.stderr b/src/test/ui/match/match-incompat-type-semi.stderr index 1a2dbbcc29fb3..008b1c1e93d6d 100644 --- a/src/test/ui/match/match-incompat-type-semi.stderr +++ b/src/test/ui/match/match-incompat-type-semi.stderr @@ -56,36 +56,32 @@ 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) { - | _____________- -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 `()` -LL | | }; - | |_____- `match` arms have incompatible types +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 5 previous errors