1
Fork 0

Reduce diagram mess in 'match arms have incompatible types' error

This commit is contained in:
David Tolnay 2020-10-22 14:20:02 -07:00
parent f82adf5bdb
commit b0059500f6
No known key found for this signature in database
GPG key ID: F9BA143B95FF6D82
4 changed files with 38 additions and 28 deletions

View file

@ -619,6 +619,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
scrut_hir_id, scrut_hir_id,
opt_suggest_box_span, opt_suggest_box_span,
arm_span, arm_span,
scrut_span,
.. ..
}) => match source { }) => match source {
hir::MatchSource::IfLetDesugar { .. } => { hir::MatchSource::IfLetDesugar { .. } => {
@ -664,18 +665,29 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
Some(ty::error::ExpectedFound { expected, .. }) => expected, Some(ty::error::ExpectedFound { expected, .. }) => expected,
_ => last_ty, _ => last_ty,
}); });
let msg = "`match` arms have incompatible types"; let source_map = self.tcx.sess.source_map();
err.span_label(cause.span, msg); let mut any_multiline_arm = source_map.is_multiline(arm_span);
if prior_arms.len() <= 4 { if prior_arms.len() <= 4 {
for sp in prior_arms { 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)); err.span_label(*sp, format!("this is found to be of type `{}`", t));
} }
} else if let Some(sp) = prior_arms.last() { } else if let Some(sp) = prior_arms.last() {
any_multiline_arm |= source_map.is_multiline(*sp);
err.span_label( err.span_label(
*sp, *sp,
format!("this and all prior arms are found to be of type `{}`", t), 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 { if let Some(sp) = semi_span {
err.span_suggestion_short( err.span_suggestion_short(
sp, sp,

View file

@ -343,6 +343,7 @@ static_assert_size!(ObligationCauseCode<'_>, 32);
#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)] #[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
pub struct MatchExpressionArmCause<'tcx> { pub struct MatchExpressionArmCause<'tcx> {
pub arm_span: Span, pub arm_span: Span,
pub scrut_span: Span,
pub semi_span: Option<Span>, pub semi_span: Option<Span>,
pub source: hir::MatchSource, pub source: hir::MatchSource,
pub prior_arms: Vec<Span>, pub prior_arms: Vec<Span>,

View file

@ -201,6 +201,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr.span, expr.span,
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
arm_span, arm_span,
scrut_span: scrut.span,
semi_span, semi_span,
source: match_src, source: match_src,
prior_arms: other_arms.clone(), prior_arms: other_arms.clone(),

View file

@ -56,36 +56,32 @@ LL | | };
error[E0308]: `match` arms have incompatible types error[E0308]: `match` arms have incompatible types
--> $DIR/match-incompat-type-semi.rs:39:17 --> $DIR/match-incompat-type-semi.rs:39:17
| |
LL | let _ = match Some(42) { LL | let _ = match Some(42) {
| _____________- | -------------- `match` arms have incompatible types
LL | | Some(x) => { LL | Some(x) => {
LL | | x LL | x
| | - this is found to be of type `{integer}` | - this is found to be of type `{integer}`
LL | | }, LL | },
LL | | None => { LL | None => {
| |_________________^ | _________________^
LL | || }, LL | | },
| ||_________^ expected integer, found `()` | |_________^ expected integer, found `()`
LL | | };
| |_____- `match` arms have incompatible types
error[E0308]: `match` arms have incompatible types error[E0308]: `match` arms have incompatible types
--> $DIR/match-incompat-type-semi.rs:50:17 --> $DIR/match-incompat-type-semi.rs:50:17
| |
LL | let _ = match Some(42) { LL | let _ = match Some(42) {
| _____________- | -------------- `match` arms have incompatible types
LL | | Some(x) => "rust-lang.org" LL | Some(x) => "rust-lang.org"
| |____________________- | ____________________-
LL | || .chars() LL | | .chars()
LL | || .skip(1) LL | | .skip(1)
LL | || .chain(Some(x as u8 as char)) LL | | .chain(Some(x as u8 as char))
LL | || .take(10) LL | | .take(10)
LL | || .any(char::is_alphanumeric), LL | | .any(char::is_alphanumeric),
| ||_______________________________________- this is found to be of type `bool` | |_______________________________________- this is found to be of type `bool`
LL | | None => {} LL | None => {}
| | ^^ expected `bool`, found `()` | ^^ expected `bool`, found `()`
LL | | };
| |_____- `match` arms have incompatible types
error: aborting due to 5 previous errors error: aborting due to 5 previous errors