Skip to content

Commit

Permalink
Rollup merge of rust-lang#57020 - estebank:return-span, r=zackmdavis
Browse files Browse the repository at this point in the history
Point to cause of `fn` expected return type

Fix rust-lang#48136.
  • Loading branch information
Centril authored Dec 23, 2018
2 parents eb24b33 + 2820dc8 commit 0c1ba07
Show file tree
Hide file tree
Showing 8 changed files with 62 additions and 6 deletions.
9 changes: 9 additions & 0 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1979,6 +1979,15 @@ pub enum FunctionRetTy {
Return(P<Ty>),
}

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 {
Expand Down
14 changes: 12 additions & 2 deletions src/librustc_typeck/check/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1169,7 +1169,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())
Expand Down Expand Up @@ -1210,13 +1209,14 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E>
(self.final_ty.unwrap_or(self.expected_ty), expression_ty)
};

let reason_label = "expected because of this statement";
let mut db;
match cause.code {
ObligationCauseCode::ReturnNoExpression => {
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);
Expand All @@ -1234,9 +1234,19 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E>
cause.span,
blk_id,
);
if let Some(sp) = fcx.ret_coercion_span.borrow().as_ref() {
if !sp.overlaps(cause.span) {
db.span_label(*sp, reason_label);
}
}
}
_ => {
db = fcx.report_mismatched_types(cause, expected, found, err);
if let Some(sp) = fcx.ret_coercion_span.borrow().as_ref() {
if !sp.overlaps(cause.span) {
db.span_label(*sp, reason_label);
}
}
}
}

Expand Down
23 changes: 22 additions & 1 deletion src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
err_count_on_creation: usize,

ret_coercion: Option<RefCell<DynamicCoerceMany<'gcx, 'tcx>>>,
ret_coercion_span: RefCell<Option<Span>>,

yield_ty: Option<Ty<'tcx>>,

Expand Down Expand Up @@ -1987,6 +1988,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
param_env,
err_count_on_creation: inh.tcx.sess.err_count(),
ret_coercion: None,
ret_coercion_span: RefCell::new(None),
yield_ty: None,
ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal,
ast::CRATE_NODE_ID)),
Expand Down Expand Up @@ -4172,11 +4174,30 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
struct_span_err!(self.tcx.sess, expr.span, E0572,
"return statement outside of function body").emit();
} else if let Some(ref e) = *expr_opt {
*self.ret_coercion_span.borrow_mut() = Some(e.span);
self.check_return_expr(e);
} else {
let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut();
*self.ret_coercion_span.borrow_mut() = Some(expr.span);
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
}
Expand Down
7 changes: 7 additions & 0 deletions src/libsyntax_pos/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,13 @@ impl Span {
span.lo <= other.lo && other.hi <= span.hi
}

/// Return `true` if `self` touches `other`.
pub fn overlaps(self, other: Span) -> bool {
let span = self.data();
let other = other.data();
span.lo < other.hi && other.lo < span.hi
}

/// Return true if the spans are equal with regards to the source text.
///
/// Use this instead of `==` when either span could be generated code,
Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/error-codes/E0069.stderr
Original file line number Diff line number Diff line change
@@ -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

Expand Down
3 changes: 3 additions & 0 deletions src/test/ui/impl-trait/equality.stderr
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
error[E0308]: mismatched types
--> $DIR/equality.rs:25:5
|
LL | return 1_i32;
| ----- expected because of this statement
LL | }
LL | 0_u32
| ^^^^^ expected i32, found u32
|
Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/ret-non-nil.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/return/return-unit-from-diverging.stderr
Original file line number Diff line number Diff line change
@@ -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

Expand Down

0 comments on commit 0c1ba07

Please sign in to comment.