Skip to content

Point at cause for expectation in return type type error #57723

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jan 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 37 additions & 5 deletions src/librustc_typeck/check/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1216,28 +1216,60 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E>
"supposed to be part of a block tail expression, but the \
expression is empty");
});
fcx.suggest_mismatched_types_on_tail(
let pointing_at_return_type = fcx.suggest_mismatched_types_on_tail(
&mut db,
expr,
expected,
found,
cause.span,
blk_id,
);
if let Some(sp) = fcx.ret_coercion_span.borrow().as_ref() {
if !sp.overlaps(cause.span) {
// FIXME: replace with navigating up the chain until hitting an fn or
// bailing if no "pass-through" Node is found, in order to provide a
// suggestion when encountering something like:
// ```
// fn foo(a: bool) -> impl Debug {
// if a {
// bar()?;
// }
// {
// let x = unsafe { bar() };
// x
// }
// }
// ```
//
// Verify that this is a tail expression of a function, otherwise the
// label pointing out the cause for the type coercion will be wrong
// as prior return coercions would not be relevant (#57664).
let parent_id = fcx.tcx.hir().get_parent_node(blk_id);
let parent = fcx.tcx.hir().get(fcx.tcx.hir().get_parent_node(parent_id));
if fcx.get_node_fn_decl(parent).is_some() && !pointing_at_return_type {
if let Some(sp) = fcx.ret_coercion_span.borrow().as_ref() {
db.span_label(*sp, reason_label);
}
}
}
_ => {
ObligationCauseCode::ReturnType(_id) => {
db = fcx.report_mismatched_types(cause, expected, found, err);
if let Some(sp) = fcx.ret_coercion_span.borrow().as_ref() {
let _id = fcx.tcx.hir().get_parent_node(_id);
let mut pointing_at_return_type = false;
if let Some((fn_decl, can_suggest)) = fcx.get_fn_decl(_id) {
pointing_at_return_type = fcx.suggest_missing_return_type(
&mut db, &fn_decl, expected, found, can_suggest);
}
if let (Some(sp), false) = (
fcx.ret_coercion_span.borrow().as_ref(),
pointing_at_return_type,
) {
if !sp.overlaps(cause.span) {
db.span_label(*sp, reason_label);
}
}
}
_ => {
db = fcx.report_mismatched_types(cause, expected, found, err);
}
}

if let Some(augment_error) = augment_error {
Expand Down
36 changes: 25 additions & 11 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4347,11 +4347,15 @@ 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);
if self.ret_coercion_span.borrow().is_none() {
*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);
if self.ret_coercion_span.borrow().is_none() {
*self.ret_coercion_span.borrow_mut() = Some(expr.span);
}
let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression);
if let Some((fn_decl, _)) = self.get_fn_decl(expr.id) {
coercion.coerce_forced_unit(
Expand Down Expand Up @@ -5089,12 +5093,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
found: Ty<'tcx>,
cause_span: Span,
blk_id: ast::NodeId,
) {
) -> bool {
self.suggest_missing_semicolon(err, expression, expected, cause_span);
let mut pointing_at_return_type = false;
if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest);
pointing_at_return_type = self.suggest_missing_return_type(
err, &fn_decl, expected, found, can_suggest);
}
self.suggest_ref_or_into(err, expression, expected, found);
pointing_at_return_type
}

pub fn suggest_ref_or_into(
Expand Down Expand Up @@ -5193,12 +5200,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
/// This routine checks if the return type is left as default, the method is not part of an
/// `impl` block and that it isn't the `main` method. If so, it suggests setting the return
/// type.
fn suggest_missing_return_type(&self,
err: &mut DiagnosticBuilder<'tcx>,
fn_decl: &hir::FnDecl,
expected: Ty<'tcx>,
found: Ty<'tcx>,
can_suggest: bool) {
fn suggest_missing_return_type(
&self,
err: &mut DiagnosticBuilder<'tcx>,
fn_decl: &hir::FnDecl,
expected: Ty<'tcx>,
found: Ty<'tcx>,
can_suggest: bool,
) -> bool {
// Only suggest changing the return type for methods that
// haven't set a return type at all (and aren't `fn main()` or an impl).
match (&fn_decl.output, found.is_suggestable(), can_suggest, expected.is_unit()) {
Expand All @@ -5208,16 +5217,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
"try adding a return type",
format!("-> {} ", self.resolve_type_vars_with_obligations(found)),
Applicability::MachineApplicable);
true
}
(&hir::FunctionRetTy::DefaultReturn(span), false, true, true) => {
err.span_label(span, "possibly return type missing here?");
true
}
(&hir::FunctionRetTy::DefaultReturn(span), _, false, true) => {
// `fn main()` must return `()`, do not suggest changing return type
err.span_label(span, "expected `()` because of default return type");
true
}
// expectation was caused by something else, not the default return
(&hir::FunctionRetTy::DefaultReturn(_), _, _, false) => {}
(&hir::FunctionRetTy::DefaultReturn(_), _, _, false) => false,
(&hir::FunctionRetTy::Return(ref ty), _, _, _) => {
// Only point to return type if the expected type is the return type, as if they
// are not, the expectation must have been caused by something else.
Expand All @@ -5229,7 +5241,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
if ty.sty == expected.sty {
err.span_label(sp, format!("expected `{}` because of return type",
expected));
return true;
}
false
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
error[E0308]: mismatched types
--> $DIR/fully-qualified-type-name2.rs:12:12
|
LL | fn bar(x: x::Foo) -> y::Foo {
| ------ expected `y::Foo` because of return type
LL | return x;
| ^ expected enum `y::Foo`, found enum `x::Foo`
|
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
error[E0308]: mismatched types
--> $DIR/fully-qualified-type-name4.rs:6:12
|
LL | fn bar(x: usize) -> Option<usize> {
| ------------- expected `std::option::Option<usize>` because of return type
LL | return x;
| ^ expected enum `std::option::Option`, found usize
|
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/liveness/liveness-forgot-ret.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/liveness-forgot-ret.rs:3:19
|
LL | fn f(a: isize) -> isize { if god_exists(a) { return 5; }; }
| - ^^^^^ expected isize, found () - expected because of this statement
| - ^^^^^ expected isize, found ()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yay, drive by fixes :)

| |
| this function's body doesn't return
|
Expand Down
17 changes: 17 additions & 0 deletions src/test/ui/point-to-type-err-cause-on-impl-trait-return-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
fn unrelated() -> Result<(), std::string::ParseError> { // #57664
let x = 0;

match x {
1 => {
let property_value_as_string = "a".parse()?;
}
2 => {
let value: &bool = unsafe { &42 };
//~^ ERROR mismatched types
}
};

Ok(())
}

fn main() {}
12 changes: 12 additions & 0 deletions src/test/ui/point-to-type-err-cause-on-impl-trait-return-2.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0308]: mismatched types
--> $DIR/point-to-type-err-cause-on-impl-trait-return-2.rs:9:41
|
LL | let value: &bool = unsafe { &42 };
| ^^^ expected bool, found integer
|
= note: expected type `&bool`
found type `&{integer}`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
36 changes: 36 additions & 0 deletions src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
fn foo() -> impl std::fmt::Display {
if false {
return 0i32;
}
1u32
//~^ ERROR mismatched types
}

fn bar() -> impl std::fmt::Display {
if false {
return 0i32;
} else {
return 1u32;
//~^ ERROR mismatched types
}
}

fn baz() -> impl std::fmt::Display {
if false {
//~^ ERROR mismatched types
return 0i32;
} else {
1u32
}
}

fn qux() -> impl std::fmt::Display {
if false {
0i32
} else {
1u32
//~^ ERROR if and else have incompatible types
}
}

fn main() {}
58 changes: 58 additions & 0 deletions src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
error[E0308]: mismatched types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:5:5
|
LL | return 0i32;
| ---- expected because of this statement
LL | }
LL | 1u32
| ^^^^ expected i32, found u32
|
= note: expected type `i32`
found type `u32`
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these errors also point at the impl Trait return type?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think they could and that would be a tad better but the errors aren't much worse off for the lack of it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filed #57743


error[E0308]: mismatched types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:13:16
|
LL | return 0i32;
| ---- expected because of this statement
LL | } else {
LL | return 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:19:5
|
LL | / if false {
LL | | //~^ ERROR mismatched types
LL | | return 0i32;
| | ---- expected because of this statement
LL | | } else {
LL | | 1u32
LL | | }
| |_____^ expected i32, found u32
|
= note: expected type `i32`
found type `u32`

error[E0308]: if and else have incompatible types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:31:9
|
LL | / if false {
LL | | 0i32
| | ---- expected because of this
LL | | } else {
LL | | 1u32
| | ^^^^ expected i32, found u32
LL | | //~^ ERROR if and else have incompatible types
LL | | }
| |_____- if and else have incompatible types
|
= note: expected type `i32`
found type `u32`

error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0308`.
3 changes: 3 additions & 0 deletions src/test/ui/proc-macro/span-preservation.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ LL | let x: usize = "hello";;;;; //~ ERROR mismatched types
error[E0308]: mismatched types
--> $DIR/span-preservation.rs:19:29
|
LL | fn b(x: Option<isize>) -> usize {
| ----- expected `usize` because of return type
LL | match x {
LL | Some(x) => { return x }, //~ ERROR mismatched types
| ^ expected usize, found isize

Expand Down
2 changes: 2 additions & 0 deletions src/test/ui/return/return-from-diverging.stderr
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
error[E0308]: mismatched types
--> $DIR/return-from-diverging.rs:4:12
|
LL | fn fail() -> ! {
| - expected `!` because of return type
LL | return "wow"; //~ ERROR mismatched types
| ^^^^^ expected !, found reference
|
Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/tail-typeck.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ error[E0308]: mismatched types
--> $DIR/tail-typeck.rs:3:26
|
LL | fn f() -> isize { return g(); }
| ^^^ expected isize, found usize
| ----- ^^^ expected isize, found usize
| |
| expected `isize` because of return type

error: aborting due to previous error

Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/wrong-ret-type.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ error[E0308]: mismatched types
--> $DIR/wrong-ret-type.rs:2:49
|
LL | fn mk_int() -> usize { let i: isize = 3; return i; }
| ^ expected usize, found isize
| ----- ^ expected usize, found isize
| |
| expected `usize` because of return type

error: aborting due to previous error

Expand Down