Only point out non-diverging arms for match suggestions

This commit is contained in:
Michael Goulet 2024-02-15 14:34:42 +00:00
parent fa9f77ff35
commit c763f833d1
7 changed files with 69 additions and 18 deletions

View file

@ -79,7 +79,7 @@ pub fn check_match(
CoerceMany::with_coercion_sites(coerce_first, arms)
};
let mut other_arms = vec![]; // Used only for diagnostics.
let mut prior_non_diverging_arms = vec![]; // Used only for diagnostics.
let mut prior_arm = None;
for arm in arms {
if let Some(e) = &arm.guard {
@ -120,7 +120,7 @@ pub fn check_match(
scrut_span: scrut.span,
scrut_hir_id: scrut.hir_id,
source: match_src,
prior_arms: other_arms.clone(),
prior_non_diverging_arms: prior_non_diverging_arms.clone(),
opt_suggest_box_span,
})),
),
@ -142,16 +142,16 @@ pub fn check_match(
false,
);
other_arms.push(arm_span);
if other_arms.len() > 5 {
other_arms.remove(0);
}
if !arm_ty.is_never() {
// When a match arm has type `!`, then it doesn't influence the expected type for
// the following arm. If all of the prior arms are `!`, then the influence comes
// from elsewhere and we shouldn't point to any previous arm.
prior_arm = Some((arm_block_id, arm_ty, arm_span));
prior_non_diverging_arms.push(arm_span);
if prior_non_diverging_arms.len() > 5 {
prior_non_diverging_arms.remove(0);
}
}
}

View file

@ -777,7 +777,7 @@ fn note_error_origin(
prior_arm_span,
prior_arm_ty,
source,
ref prior_arms,
ref prior_non_diverging_arms,
opt_suggest_box_span,
scrut_span,
scrut_hir_id,
@ -817,12 +817,12 @@ fn note_error_origin(
});
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 {
if prior_non_diverging_arms.len() <= 4 {
for sp in prior_non_diverging_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() {
} else if let Some(sp) = prior_non_diverging_arms.last() {
any_multiline_arm |= source_map.is_multiline(*sp);
err.span_label(
*sp,
@ -865,7 +865,10 @@ fn note_error_origin(
self.suggest_boxing_for_return_impl_trait(
err,
ret_sp,
prior_arms.iter().chain(std::iter::once(&arm_span)).copied(),
prior_non_diverging_arms
.iter()
.chain(std::iter::once(&arm_span))
.copied(),
);
}
}

View file

@ -203,10 +203,10 @@ pub(super) fn suggest_await_on_expect_found(
})
}
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
prior_arms,
prior_non_diverging_arms,
..
}) => {
if let [.., arm_span] = &prior_arms[..] {
if let [.., arm_span] = &prior_non_diverging_arms[..] {
Some(ConsiderAddingAwait::BothFuturesSugg {
first: arm_span.shrink_to_hi(),
second: exp_span.shrink_to_hi(),
@ -234,11 +234,14 @@ pub(super) fn suggest_await_on_expect_found(
Some(ConsiderAddingAwait::FutureSugg { span: then_span.shrink_to_hi() })
}
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
ref prior_arms,
ref prior_non_diverging_arms,
..
}) => Some({
ConsiderAddingAwait::FutureSuggMultiple {
spans: prior_arms.iter().map(|arm| arm.shrink_to_hi()).collect(),
spans: prior_non_diverging_arms
.iter()
.map(|arm| arm.shrink_to_hi())
.collect(),
}
}),
_ => None,

View file

@ -571,7 +571,7 @@ pub struct MatchExpressionArmCause<'tcx> {
pub scrut_span: Span,
pub scrut_hir_id: hir::HirId,
pub source: hir::MatchSource,
pub prior_arms: Vec<Span>,
pub prior_non_diverging_arms: Vec<Span>,
pub opt_suggest_box_span: Option<Span>,
}

View file

@ -0,0 +1,17 @@
fn main() {
let m = 42u32;
let value = 'out: {
match m {
1 => break 'out Some(1u16),
2 => Some(2u16),
3 => break 'out Some(3u16),
4 => break 'out Some(4u16),
5 => break 'out Some(5u16),
_ => {}
//~^ ERROR `match` arms have incompatible types
}
None
};
}

View file

@ -0,0 +1,25 @@
error[E0308]: `match` arms have incompatible types
--> $DIR/dont-highlight-diverging-arms.rs:11:18
|
LL | / match m {
LL | | 1 => break 'out Some(1u16),
LL | | 2 => Some(2u16),
| | ---------- this is found to be of type `Option<u16>`
LL | | 3 => break 'out Some(3u16),
... |
LL | | _ => {}
| | ^^ expected `Option<u16>`, found `()`
LL | |
LL | | }
| |_________- `match` arms have incompatible types
|
= note: expected enum `Option<u16>`
found unit type `()`
help: consider using a semicolon here, but this will discard any values in the match arms
|
LL | };
| +
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0308`.

View file

@ -3,11 +3,14 @@ error[E0308]: `match` arms have incompatible types
|
LL | / match E::F {
LL | | E::A => 1,
| | - this is found to be of type `{integer}`
LL | | E::B => 2,
| | - this is found to be of type `{integer}`
LL | | E::C => 3,
| | - this is found to be of type `{integer}`
LL | | E::D => 4,
| | - this is found to be of type `{integer}`
LL | | E::E => unimplemented!(""),
| | ------------------ this and all prior arms are found to be of type `{integer}`
LL | | E::F => "",
| | ^^ expected integer, found `&str`
LL | | };