Rollup merge of #64083 - estebank:tweak-e0308, r=oli-obk

Point at appropriate arm on type error on if/else/match with one non-! arm

Fix https://github.com/rust-lang/rust/issues/61281.
This commit is contained in:
Mazdak Farrokhzad 2019-09-05 12:11:16 +02:00 committed by GitHub
commit 59237ec665
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 123 additions and 19 deletions

View File

@ -3687,6 +3687,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
} }
/// If `expr` is a `match` expression that has only one non-`!` arm, use that arm's tail
/// expression's `Span`, otherwise return `expr.span`. This is done to give better errors
/// when given code like the following:
/// ```text
/// if false { return 0i32; } else { 1u32 }
/// // ^^^^ point at this instead of the whole `if` expression
/// ```
fn get_expr_coercion_span(&self, expr: &hir::Expr) -> syntax_pos::Span {
if let hir::ExprKind::Match(_, arms, _) = &expr.node {
let arm_spans: Vec<Span> = arms.iter().filter_map(|arm| {
self.in_progress_tables
.and_then(|tables| tables.borrow().node_type_opt(arm.body.hir_id))
.and_then(|arm_ty| {
if arm_ty.is_never() {
None
} else {
Some(match &arm.body.node {
// Point at the tail expression when possible.
hir::ExprKind::Block(block, _) => block.expr
.as_ref()
.map(|e| e.span)
.unwrap_or(block.span),
_ => arm.body.span,
})
}
})
}).collect();
if arm_spans.len() == 1 {
return arm_spans[0];
}
}
expr.span
}
fn check_block_with_expected( fn check_block_with_expected(
&self, &self,
blk: &'tcx hir::Block, blk: &'tcx hir::Block,
@ -3746,12 +3780,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let coerce = ctxt.coerce.as_mut().unwrap(); let coerce = ctxt.coerce.as_mut().unwrap();
if let Some(tail_expr_ty) = tail_expr_ty { if let Some(tail_expr_ty) = tail_expr_ty {
let tail_expr = tail_expr.unwrap(); let tail_expr = tail_expr.unwrap();
let cause = self.cause(tail_expr.span, let span = self.get_expr_coercion_span(tail_expr);
ObligationCauseCode::BlockTailExpression(blk.hir_id)); let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id));
coerce.coerce(self, coerce.coerce(self, &cause, tail_expr, tail_expr_ty);
&cause,
tail_expr,
tail_expr_ty);
} else { } else {
// Subtle: if there is no explicit tail expression, // Subtle: if there is no explicit tail expression,
// that is typically equivalent to a tail expression // that is typically equivalent to a tail expression

View File

@ -17,10 +17,10 @@ fn bar() -> impl std::fmt::Display {
fn baz() -> impl std::fmt::Display { fn baz() -> impl std::fmt::Display {
if false { if false {
//~^ ERROR mismatched types
return 0i32; return 0i32;
} else { } else {
1u32 1u32
//~^ ERROR mismatched types
} }
} }
@ -33,4 +33,33 @@ fn qux() -> impl std::fmt::Display {
} }
} }
fn bat() -> impl std::fmt::Display {
match 13 {
0 => return 0i32,
_ => 1u32,
//~^ ERROR mismatched types
}
}
fn can() -> impl std::fmt::Display {
match 13 {
//~^ ERROR mismatched types
0 => return 0i32,
1 => 1u32,
_ => 2u32,
}
}
fn cat() -> impl std::fmt::Display {
match 13 {
0 => {
return 0i32;
}
_ => {
1u32
//~^ ERROR mismatched types
}
}
}
fn main() {} fn main() {}

View File

@ -29,18 +29,16 @@ LL | return 1u32;
found type `u32` found type `u32`
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:19:5 --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:22:9
| |
LL | fn baz() -> impl std::fmt::Display { LL | fn baz() -> impl std::fmt::Display {
| ---------------------- expected because this return type... | ---------------------- expected because this return type...
LL | / if false { LL | if false {
LL | | LL | return 0i32;
LL | | return 0i32; | ---- ...is found to be `i32` here
| | ---- ...is found to be `i32` here LL | } else {
LL | | } else { LL | 1u32
LL | | 1u32 | ^^^^ expected i32, found u32
LL | | }
| |_____^ expected i32, found u32
| |
= note: expected type `i32` = note: expected type `i32`
found type `u32` found type `u32`
@ -61,6 +59,52 @@ LL | | }
= note: expected type `i32` = note: expected type `i32`
found type `u32` found type `u32`
error: aborting due to 4 previous errors error[E0308]: mismatched types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:39:14
|
LL | fn bat() -> impl std::fmt::Display {
| ---------------------- expected because this return type...
LL | match 13 {
LL | 0 => return 0i32,
| ---- ...is found to be `i32` here
LL | _ => 1u32,
| ^^^^ expected i32, found u32
|
= note: expected type `i32`
found type `u32`
error[E0308]: mismatched types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:45:5
|
LL | fn can() -> impl std::fmt::Display {
| ---------------------- expected because this return type...
LL | / match 13 {
LL | |
LL | | 0 => return 0i32,
| | ---- ...is found to be `i32` here
LL | | 1 => 1u32,
LL | | _ => 2u32,
LL | | }
| |_____^ expected i32, found u32
|
= note: expected type `i32`
found type `u32`
error[E0308]: mismatched types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:59:13
|
LL | fn cat() -> impl std::fmt::Display {
| ---------------------- expected because this return type...
...
LL | return 0i32;
| ---- ...is found to be `i32` here
...
LL | 1u32
| ^^^^ expected i32, found u32
|
= note: expected type `i32`
found type `u32`
error: aborting due to 7 previous errors
For more information about this error, try `rustc --explain E0308`. For more information about this error, try `rustc --explain E0308`.