Stop using the whole match expr span for an arm's obligation span

This commit is contained in:
Michael Goulet 2024-10-27 22:35:17 +00:00
parent 5f5c243ca0
commit 2507e83d7b
5 changed files with 18 additions and 21 deletions

View File

@ -94,14 +94,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(None, arm.body.span)
};
let (span, code) = match prior_arm {
let code = match prior_arm {
// The reason for the first arm to fail is not that the match arms diverge,
// but rather that there's a prior obligation that doesn't hold.
None => {
(arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id, match_src))
}
Some((prior_arm_block_id, prior_arm_ty, prior_arm_span)) => (
expr.span,
None => ObligationCauseCode::BlockTailExpression(arm.body.hir_id, match_src),
Some((prior_arm_block_id, prior_arm_ty, prior_arm_span)) => {
ObligationCauseCode::MatchExpressionArm(Box::new(MatchExpressionArmCause {
arm_block_id,
arm_span,
@ -110,13 +107,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
prior_arm_ty,
prior_arm_span,
scrut_span: scrut.span,
expr_span: expr.span,
source: match_src,
prior_non_diverging_arms: prior_non_diverging_arms.clone(),
tail_defines_return_position_impl_trait,
})),
),
}))
}
};
let cause = self.cause(span, code);
let cause = self.cause(arm_span, code);
// This is the moral equivalent of `coercion.coerce(self, cause, arm.body, arm_ty)`.
// We use it this way to be able to expand on the potential error and detect when a

View File

@ -519,6 +519,8 @@ pub struct MatchExpressionArmCause<'tcx> {
pub prior_arm_span: Span,
pub scrut_span: Span,
pub source: hir::MatchSource,
// Span of the *whole* match expr
pub expr_span: Span,
pub prior_non_diverging_arms: Vec<Span>,
// Is the expectation of this match expression an RPIT?
pub tail_defines_return_position_impl_trait: Option<LocalDefId>,

View File

@ -412,6 +412,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
source,
ref prior_non_diverging_arms,
scrut_span,
expr_span,
..
}) => match source {
hir::MatchSource::TryDesugar(scrut_hir_id) => {
@ -460,12 +461,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
format!("this and all prior arms are found to be of type `{t}`"),
);
}
let outer = if any_multiline_arm || !source_map.is_multiline(cause.span) {
let outer = if any_multiline_arm || !source_map.is_multiline(expr_span) {
// Cover just `match` and the scrutinee expression, not
// the entire match body, to reduce diagram noise.
cause.span.shrink_to_lo().to(scrut_span)
expr_span.shrink_to_lo().to(scrut_span)
} else {
cause.span
expr_span
};
let msg = "`match` arms have incompatible types";
err.span_label(outer, msg);

View File

@ -22,8 +22,8 @@ fn main() {
Some(()) => &S,
None => &R, //~ ERROR E0308
}
let t: &dyn Trait = match opt() { //~ ERROR E0038
let t: &dyn Trait = match opt() {
Some(()) => &S, //~ ERROR E0038
None => &R,
None => &R, //~ ERROR E0038
};
}

View File

@ -31,14 +31,10 @@ LL | trait Trait: Sized {}
= note: required for the cast from `&S` to `&dyn Trait`
error[E0038]: the trait `Trait` cannot be made into an object
--> $DIR/wf-dyn-incompat-trait-obj-match.rs:25:25
--> $DIR/wf-dyn-incompat-trait-obj-match.rs:27:17
|
LL | let t: &dyn Trait = match opt() {
| _________________________^
LL | | Some(()) => &S,
LL | | None => &R,
LL | | };
| |_____^ `Trait` cannot be made into an object
LL | None => &R,
| ^^ `Trait` cannot be made into an object
|
note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/wf-dyn-incompat-trait-obj-match.rs:6:14