Skip to content

Commit 1893c61

Browse files
authored
Rollup merge of rust-lang#64083 - estebank:tweak-e0308, r=oli-obk
Point at appropriate arm on type error on if/else/match with one non-! arm Fix rust-lang#61281.
2 parents 49bc3f5 + c430d74 commit 1893c61

File tree

3 files changed

+123
-19
lines changed

3 files changed

+123
-19
lines changed

src/librustc_typeck/check/mod.rs

+37-6
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 better 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

+30-1
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

@@ -33,4 +33,33 @@ fn qux() -> impl std::fmt::Display {
3333
}
3434
}
3535

36+
fn bat() -> impl std::fmt::Display {
37+
match 13 {
38+
0 => return 0i32,
39+
_ => 1u32,
40+
//~^ ERROR mismatched types
41+
}
42+
}
43+
44+
fn can() -> impl std::fmt::Display {
45+
match 13 {
46+
//~^ ERROR mismatched types
47+
0 => return 0i32,
48+
1 => 1u32,
49+
_ => 2u32,
50+
}
51+
}
52+
53+
fn cat() -> impl std::fmt::Display {
54+
match 13 {
55+
0 => {
56+
return 0i32;
57+
}
58+
_ => {
59+
1u32
60+
//~^ ERROR mismatched types
61+
}
62+
}
63+
}
64+
3665
fn main() {}

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

+56-12
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`
@@ -61,6 +59,52 @@ LL | | }
6159
= note: expected type `i32`
6260
found type `u32`
6361

64-
error: aborting due to 4 previous errors
62+
error[E0308]: mismatched types
63+
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:39:14
64+
|
65+
LL | fn bat() -> impl std::fmt::Display {
66+
| ---------------------- expected because this return type...
67+
LL | match 13 {
68+
LL | 0 => return 0i32,
69+
| ---- ...is found to be `i32` here
70+
LL | _ => 1u32,
71+
| ^^^^ expected i32, found u32
72+
|
73+
= note: expected type `i32`
74+
found type `u32`
75+
76+
error[E0308]: mismatched types
77+
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:45:5
78+
|
79+
LL | fn can() -> impl std::fmt::Display {
80+
| ---------------------- expected because this return type...
81+
LL | / match 13 {
82+
LL | |
83+
LL | | 0 => return 0i32,
84+
| | ---- ...is found to be `i32` here
85+
LL | | 1 => 1u32,
86+
LL | | _ => 2u32,
87+
LL | | }
88+
| |_____^ expected i32, found u32
89+
|
90+
= note: expected type `i32`
91+
found type `u32`
92+
93+
error[E0308]: mismatched types
94+
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:59:13
95+
|
96+
LL | fn cat() -> impl std::fmt::Display {
97+
| ---------------------- expected because this return type...
98+
...
99+
LL | return 0i32;
100+
| ---- ...is found to be `i32` here
101+
...
102+
LL | 1u32
103+
| ^^^^ expected i32, found u32
104+
|
105+
= note: expected type `i32`
106+
found type `u32`
107+
108+
error: aborting due to 7 previous errors
65109

66110
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)