Skip to content

Commit 334d465

Browse files
committed
Point at appropriate arm on type error on if/else/match with one non-! arm
1 parent dfd43f0 commit 334d465

File tree

3 files changed

+47
-18
lines changed

3 files changed

+47
-18
lines changed

src/librustc_typeck/check/mod.rs

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3687,6 +3687,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
36873687
}
36883688
}
36893689

3690+
/// If `expr` is a `match` expression that has only one non-`!` arm, use that arm's tail
3691+
/// expression's `Span`, otherwise return `expr.span`. This is done to give bettern errors
3692+
/// when given code like the following:
3693+
/// ```text
3694+
/// if false { return 0i32; } else { 1u32 }
3695+
/// // ^^^^ point at this instead of the whole `if` expression
3696+
/// ```
3697+
fn get_expr_coercion_span(&self, expr: &hir::Expr) -> syntax_pos::Span {
3698+
if let hir::ExprKind::Match(_, arms, _) = &expr.node {
3699+
let arm_spans: Vec<Span> = arms.iter().filter_map(|arm| {
3700+
self.in_progress_tables
3701+
.and_then(|tables| tables.borrow().node_type_opt(arm.body.hir_id))
3702+
.and_then(|arm_ty| {
3703+
if arm_ty.is_never() {
3704+
None
3705+
} else {
3706+
Some(match &arm.body.node {
3707+
// Point at the tail expression when possible.
3708+
hir::ExprKind::Block(block, _) => block.expr
3709+
.as_ref()
3710+
.map(|e| e.span)
3711+
.unwrap_or(block.span),
3712+
_ => arm.body.span,
3713+
})
3714+
}
3715+
})
3716+
}).collect();
3717+
if arm_spans.len() == 1 {
3718+
return arm_spans[0];
3719+
}
3720+
}
3721+
expr.span
3722+
}
3723+
36903724
fn check_block_with_expected(
36913725
&self,
36923726
blk: &'tcx hir::Block,
@@ -3746,12 +3780,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
37463780
let coerce = ctxt.coerce.as_mut().unwrap();
37473781
if let Some(tail_expr_ty) = tail_expr_ty {
37483782
let tail_expr = tail_expr.unwrap();
3749-
let cause = self.cause(tail_expr.span,
3750-
ObligationCauseCode::BlockTailExpression(blk.hir_id));
3751-
coerce.coerce(self,
3752-
&cause,
3753-
tail_expr,
3754-
tail_expr_ty);
3783+
let span = self.get_expr_coercion_span(tail_expr);
3784+
let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id));
3785+
coerce.coerce(self, &cause, tail_expr, tail_expr_ty);
37553786
} else {
37563787
// Subtle: if there is no explicit tail expression,
37573788
// that is typically equivalent to a tail expression

src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ fn bar() -> impl std::fmt::Display {
1717

1818
fn baz() -> impl std::fmt::Display {
1919
if false {
20-
//~^ ERROR mismatched types
2120
return 0i32;
2221
} else {
2322
1u32
23+
//~^ ERROR mismatched types
2424
}
2525
}
2626

src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,16 @@ LL | return 1u32;
2929
found type `u32`
3030

3131
error[E0308]: mismatched types
32-
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:19:5
32+
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:22:9
3333
|
34-
LL | fn baz() -> impl std::fmt::Display {
35-
| ---------------------- expected because this return type...
36-
LL | / if false {
37-
LL | |
38-
LL | | return 0i32;
39-
| | ---- ...is found to be `i32` here
40-
LL | | } else {
41-
LL | | 1u32
42-
LL | | }
43-
| |_____^ expected i32, found u32
34+
LL | fn baz() -> impl std::fmt::Display {
35+
| ---------------------- expected because this return type...
36+
LL | if false {
37+
LL | return 0i32;
38+
| ---- ...is found to be `i32` here
39+
LL | } else {
40+
LL | 1u32
41+
| ^^^^ expected i32, found u32
4442
|
4543
= note: expected type `i32`
4644
found type `u32`

0 commit comments

Comments
 (0)