diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 156d55b9e2fe..58733a83b253 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1979,6 +1979,15 @@ pub enum FunctionRetTy { Return(P), } +impl fmt::Display for FunctionRetTy { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Return(ref ty) => print::to_string(print::NO_ANN, |s| s.print_type(ty)).fmt(f), + DefaultReturn(_) => "()".fmt(f), + } + } +} + impl FunctionRetTy { pub fn span(&self) -> Span { match *self { diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 8d844fe3a69e..0b99a30b67dc 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -1143,7 +1143,6 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> // `expression_ty` will be unit). // // Another example is `break` with no argument expression. - assert!(expression_ty.is_unit()); assert!(expression_ty.is_unit(), "if let hack without unit type"); fcx.at(cause, fcx.param_env) .eq_exp(label_expression_as_expected, expression_ty, self.merged_ty()) @@ -1190,7 +1189,7 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> db = struct_span_err!( fcx.tcx.sess, cause.span, E0069, "`return;` in a function whose return type is not `()`"); - db.span_label(cause.span, "return type is not ()"); + db.span_label(cause.span, "return type is not `()`"); } ObligationCauseCode::BlockTailExpression(blk_id) => { db = fcx.report_mismatched_types(cause, expected, found, err); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 8901f4b6b291..d40afbbc3025 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4103,7 +4103,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else { let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut(); let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression); - coercion.coerce_forced_unit(self, &cause, &mut |_| (), true); + if let Some((fn_decl, _)) = self.get_fn_decl(expr.id) { + coercion.coerce_forced_unit( + self, + &cause, + &mut |db| { + db.span_label( + fn_decl.output.span(), + format!( + "expected `{}` because of this return type", + fn_decl.output, + ), + ); + }, + true, + ); + } else { + coercion.coerce_forced_unit(self, &cause, &mut |_| (), true); + } } tcx.types.never } diff --git a/src/test/ui/error-codes/E0069.stderr b/src/test/ui/error-codes/E0069.stderr index 0ba1ed456635..12b778f42e22 100644 --- a/src/test/ui/error-codes/E0069.stderr +++ b/src/test/ui/error-codes/E0069.stderr @@ -1,8 +1,10 @@ error[E0069]: `return;` in a function whose return type is not `()` --> $DIR/E0069.rs:12:5 | +LL | fn foo() -> u8 { + | -- expected `u8` because of this return type LL | return; - | ^^^^^^ return type is not () + | ^^^^^^ return type is not `()` error: aborting due to previous error diff --git a/src/test/ui/ret-non-nil.stderr b/src/test/ui/ret-non-nil.stderr index 01f126bd11ea..e0fdc8c67edf 100644 --- a/src/test/ui/ret-non-nil.stderr +++ b/src/test/ui/ret-non-nil.stderr @@ -2,7 +2,9 @@ error[E0069]: `return;` in a function whose return type is not `()` --> $DIR/ret-non-nil.rs:15:19 | LL | fn g() -> isize { return; } - | ^^^^^^ return type is not () + | ----- ^^^^^^ return type is not `()` + | | + | expected `isize` because of this return type error: aborting due to previous error diff --git a/src/test/ui/return/return-unit-from-diverging.stderr b/src/test/ui/return/return-unit-from-diverging.stderr index 38d4ca37366f..5a9f0877cc6b 100644 --- a/src/test/ui/return/return-unit-from-diverging.stderr +++ b/src/test/ui/return/return-unit-from-diverging.stderr @@ -1,8 +1,10 @@ error[E0069]: `return;` in a function whose return type is not `()` --> $DIR/return-unit-from-diverging.rs:15:5 | +LL | fn fail() -> ! { + | - expected `!` because of this return type LL | return; //~ ERROR in a function whose return type is not - | ^^^^^^ return type is not () + | ^^^^^^ return type is not `()` error: aborting due to previous error