diff options
author | Yuki Okushi <huyuumi.dev@gmail.com> | 2020-10-23 18:26:40 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-23 18:26:40 +0900 |
commit | 7ba519ec50cf2c48bae64eead90c3fda9110920b (patch) | |
tree | a16fe408b9992a4ce5412336c6ed50a318db3d39 | |
parent | 3f462c22b53ee5ae2f56e2b268a15fd4dab9d22c (diff) | |
parent | b0059500f6765612fbda6d33240116f7520d433a (diff) | |
download | rust-7ba519ec50cf2c48bae64eead90c3fda9110920b.tar.gz |
Rollup merge of #78255 - dtolnay:match, r=lcnr
Reduce diagram mess in 'match arms have incompatible types' error
I noticed this wild diagram in https://twitter.com/a_hoverbear/status/1318960787105353728 which I think does not benefit from the big outer vertical span.
This PR shrinks the outer span to cover just the `match` keyword and scrutinee expression *if* at least one of the highlighted match arms involved in the error is multiline.
**Before:**
<pre>
<b>error[E0308]: `match` arms have incompatible types</b>
<b>--></b> src/topology/builder.rs:141:35
<b>|</b>
<b>120 |</b> let transform = match transform {
<b>| _________________________-</b>
<b>121 | |</b> Transform::Function(t) => {
<b>| _|_______________________________________-</b>
<b>122 | | |</b> filter_event_type(input_rx, input_type).compat().flat_map(|v| {
<b>123 | | |</b> futures::stream::iter(match v {
<b>124 | | |</b> Err(e) => {
<b>... | |</b>
<b>139 | | |</b> .compat();
<b>140 | | |</b> }
<b>| |_|_____________- this is found to be of type `()`</b>
<b>141 | |</b> Transform::Task(t) => t
<b>| _|___________________________________^</b>
<b>142 | | |</b> .transform(filter_event_type(input_rx, input_type))
<b>143 | | |</b> .forward(output)
<b>144 | | |</b> .map(|_| debug!("Finished"))
<b>145 | | |</b> .compat(),
<b>| |_|_________________________^ expected `()`, found struct `futures::compat::Compat01As03`</b>
<b>146 | |</b> };
<b>| |_________- `match` arms have incompatible types</b>
<b>|</b>
<b>= note:</b> expected type `<b>()</b>`
found struct `<b>futures::compat::Compat01As03<futures::Map<futures::stream::Forward<std::boxed::Box<dyn futures::Stream<Error = (), Item = event::Event> + std::marker::Send>, topology::fanout::Fanout>, [closure@src/topology/builder.rs:144:22: 144:44]>></b>`
</pre>
**After:**
<pre>
<b>error[E0308]: `match` arms have incompatible types</b>
<b>--></b> src/topology/builder.rs:141:35
<b>|</b>
<b>120 |</b> let transform = match transform {
<b>| --------------- `match` arms have incompatible types</b>
<b>121 |</b> Transform::Function(t) => {
<b>| _________________________________________-</b>
<b>122 | |</b> filter_event_type(input_rx, input_type).compat().flat_map(|v| {
<b>123 | |</b> futures::stream::iter(match v {
<b>124 | |</b> Err(e) => {
<b>... |</b>
<b>139 | |</b> .compat();
<b>140 | |</b> }
<b>| |_______________- this is found to be of type `()`</b>
<b>141 |</b> Transform::Task(t) => t
<b>| _____________________________________^</b>
<b>142 | |</b> .transform(filter_event_type(input_rx, input_type))
<b>143 | |</b> .forward(output)
<b>144 | |</b> .map(|_| debug!("Finished"))
<b>145 | |</b> .compat(),
<b>| |___________________________^ expected `()`, found struct `futures::compat::Compat01As03`</b>
<b>|</b>
<b>= note:</b> expected type `<b>()</b>`
found struct `<b>futures::compat::Compat01As03<futures::Map<futures::stream::Forward<std::boxed::Box<dyn futures::Stream<Error = (), Item = event::Event> + std::marker::Send>, topology::fanout::Fanout>, [closure@src/topology/builder.rs:144:22: 144:44]>></b>`
</pre>
FYI @Hoverbear
-rw-r--r-- | compiler/rustc_infer/src/infer/error_reporting/mod.rs | 16 | ||||
-rw-r--r-- | compiler/rustc_middle/src/traits/mod.rs | 1 | ||||
-rw-r--r-- | compiler/rustc_typeck/src/check/_match.rs | 1 | ||||
-rw-r--r-- | src/test/ui/match/match-incompat-type-semi.rs | 10 | ||||
-rw-r--r-- | src/test/ui/match/match-incompat-type-semi.stderr | 40 |
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`. |