Skip to content

Commit 174dfb8

Browse files
authored
Rollup merge of rust-lang#57020 - estebank:return-span, r=zackmdavis
Point to cause of `fn` expected return type Fix rust-lang#48136.
2 parents d875fcd + 2820dc8 commit 174dfb8

File tree

8 files changed

+62
-6
lines changed

8 files changed

+62
-6
lines changed

src/librustc/hir/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1979,6 +1979,15 @@ pub enum FunctionRetTy {
19791979
Return(P<Ty>),
19801980
}
19811981

1982+
impl fmt::Display for FunctionRetTy {
1983+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1984+
match self {
1985+
Return(ref ty) => print::to_string(print::NO_ANN, |s| s.print_type(ty)).fmt(f),
1986+
DefaultReturn(_) => "()".fmt(f),
1987+
}
1988+
}
1989+
}
1990+
19821991
impl FunctionRetTy {
19831992
pub fn span(&self) -> Span {
19841993
match *self {

src/librustc_typeck/check/coercion.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -1169,7 +1169,6 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E>
11691169
// `expression_ty` will be unit).
11701170
//
11711171
// Another example is `break` with no argument expression.
1172-
assert!(expression_ty.is_unit());
11731172
assert!(expression_ty.is_unit(), "if let hack without unit type");
11741173
fcx.at(cause, fcx.param_env)
11751174
.eq_exp(label_expression_as_expected, expression_ty, self.merged_ty())
@@ -1210,13 +1209,14 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E>
12101209
(self.final_ty.unwrap_or(self.expected_ty), expression_ty)
12111210
};
12121211

1212+
let reason_label = "expected because of this statement";
12131213
let mut db;
12141214
match cause.code {
12151215
ObligationCauseCode::ReturnNoExpression => {
12161216
db = struct_span_err!(
12171217
fcx.tcx.sess, cause.span, E0069,
12181218
"`return;` in a function whose return type is not `()`");
1219-
db.span_label(cause.span, "return type is not ()");
1219+
db.span_label(cause.span, "return type is not `()`");
12201220
}
12211221
ObligationCauseCode::BlockTailExpression(blk_id) => {
12221222
db = fcx.report_mismatched_types(cause, expected, found, err);
@@ -1234,9 +1234,19 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E>
12341234
cause.span,
12351235
blk_id,
12361236
);
1237+
if let Some(sp) = fcx.ret_coercion_span.borrow().as_ref() {
1238+
if !sp.overlaps(cause.span) {
1239+
db.span_label(*sp, reason_label);
1240+
}
1241+
}
12371242
}
12381243
_ => {
12391244
db = fcx.report_mismatched_types(cause, expected, found, err);
1245+
if let Some(sp) = fcx.ret_coercion_span.borrow().as_ref() {
1246+
if !sp.overlaps(cause.span) {
1247+
db.span_label(*sp, reason_label);
1248+
}
1249+
}
12401250
}
12411251
}
12421252

src/librustc_typeck/check/mod.rs

+22-1
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
538538
err_count_on_creation: usize,
539539

540540
ret_coercion: Option<RefCell<DynamicCoerceMany<'gcx, 'tcx>>>,
541+
ret_coercion_span: RefCell<Option<Span>>,
541542

542543
yield_ty: Option<Ty<'tcx>>,
543544

@@ -1987,6 +1988,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
19871988
param_env,
19881989
err_count_on_creation: inh.tcx.sess.err_count(),
19891990
ret_coercion: None,
1991+
ret_coercion_span: RefCell::new(None),
19901992
yield_ty: None,
19911993
ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal,
19921994
ast::CRATE_NODE_ID)),
@@ -4172,11 +4174,30 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
41724174
struct_span_err!(self.tcx.sess, expr.span, E0572,
41734175
"return statement outside of function body").emit();
41744176
} else if let Some(ref e) = *expr_opt {
4177+
*self.ret_coercion_span.borrow_mut() = Some(e.span);
41754178
self.check_return_expr(e);
41764179
} else {
41774180
let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut();
4181+
*self.ret_coercion_span.borrow_mut() = Some(expr.span);
41784182
let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression);
4179-
coercion.coerce_forced_unit(self, &cause, &mut |_| (), true);
4183+
if let Some((fn_decl, _)) = self.get_fn_decl(expr.id) {
4184+
coercion.coerce_forced_unit(
4185+
self,
4186+
&cause,
4187+
&mut |db| {
4188+
db.span_label(
4189+
fn_decl.output.span(),
4190+
format!(
4191+
"expected `{}` because of this return type",
4192+
fn_decl.output,
4193+
),
4194+
);
4195+
},
4196+
true,
4197+
);
4198+
} else {
4199+
coercion.coerce_forced_unit(self, &cause, &mut |_| (), true);
4200+
}
41804201
}
41814202
tcx.types.never
41824203
}

src/libsyntax_pos/lib.rs

+7
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,13 @@ impl Span {
334334
span.lo <= other.lo && other.hi <= span.hi
335335
}
336336

337+
/// Return `true` if `self` touches `other`.
338+
pub fn overlaps(self, other: Span) -> bool {
339+
let span = self.data();
340+
let other = other.data();
341+
span.lo < other.hi && other.lo < span.hi
342+
}
343+
337344
/// Return true if the spans are equal with regards to the source text.
338345
///
339346
/// Use this instead of `==` when either span could be generated code,

src/test/ui/error-codes/E0069.stderr

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
error[E0069]: `return;` in a function whose return type is not `()`
22
--> $DIR/E0069.rs:12:5
33
|
4+
LL | fn foo() -> u8 {
5+
| -- expected `u8` because of this return type
46
LL | return;
5-
| ^^^^^^ return type is not ()
7+
| ^^^^^^ return type is not `()`
68

79
error: aborting due to previous error
810

src/test/ui/impl-trait/equality.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
error[E0308]: mismatched types
22
--> $DIR/equality.rs:25:5
33
|
4+
LL | return 1_i32;
5+
| ----- expected because of this statement
6+
LL | }
47
LL | 0_u32
58
| ^^^^^ expected i32, found u32
69
|

src/test/ui/ret-non-nil.stderr

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ error[E0069]: `return;` in a function whose return type is not `()`
22
--> $DIR/ret-non-nil.rs:15:19
33
|
44
LL | fn g() -> isize { return; }
5-
| ^^^^^^ return type is not ()
5+
| ----- ^^^^^^ return type is not `()`
6+
| |
7+
| expected `isize` because of this return type
68

79
error: aborting due to previous error
810

src/test/ui/return/return-unit-from-diverging.stderr

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
error[E0069]: `return;` in a function whose return type is not `()`
22
--> $DIR/return-unit-from-diverging.rs:15:5
33
|
4+
LL | fn fail() -> ! {
5+
| - expected `!` because of this return type
46
LL | return; //~ ERROR in a function whose return type is not
5-
| ^^^^^^ return type is not ()
7+
| ^^^^^^ return type is not `()`
68

79
error: aborting due to previous error
810

0 commit comments

Comments
 (0)