Auto merge of #43484 - estebank:point-to-return, r=arielb1

Point at return type always when type mismatch against it

Before this, the diagnostic errors would only point at the return type
when changing it would be a possible solution to a type error. Add a
label to the return type without a suggestion to change in order to make
the source of the expected type obvious.

Follow up to #42850, fixes #25133, fixes #41897.
This commit is contained in:
bors 2017-08-09 19:50:03 +00:00
commit f142499539
8 changed files with 71 additions and 26 deletions

View File

@ -491,6 +491,7 @@ impl<'tcx> TyS<'tcx> {
TypeVariants::TyFnPtr(..) |
TypeVariants::TyDynamic(..) |
TypeVariants::TyClosure(..) |
TypeVariants::TyInfer(..) |
TypeVariants::TyProjection(..) => false,
_ => true,
}

View File

@ -4229,8 +4229,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
ty
}
/// Given a `NodeId`, return the `FnDecl` of the method it is enclosed by and whether it is
/// `fn main` if it is a method, `None` otherwise.
/// Given a `NodeId`, return the `FnDecl` of the method it is enclosed by and whether a
/// suggetion can be made, `None` otherwise.
pub fn get_fn_decl(&self, blk_id: ast::NodeId) -> Option<(hir::FnDecl, bool)> {
// Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
// `while` before reaching it, as block tail returns are not available in them.
@ -4241,14 +4241,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
name, node: hir::ItemFn(ref decl, ..), ..
}) = parent {
decl.clone().and_then(|decl| {
// This is less than ideal, it will not present the return type span on any
// method called `main`, regardless of whether it is actually the entry point.
Some((decl, name == Symbol::intern("main")))
// This is less than ideal, it will not suggest a return type span on any
// method called `main`, regardless of whether it is actually the entry point,
// but it will still present it as the reason for the expected type.
Some((decl, name != Symbol::intern("main")))
})
} else if let Node::NodeTraitItem(&hir::TraitItem {
node: hir::TraitItemKind::Method(hir::MethodSig {
ref decl, ..
}, ..), ..
}) = parent {
decl.clone().and_then(|decl| {
Some((decl, true))
})
} else if let Node::NodeImplItem(&hir::ImplItem {
node: hir::ImplItemKind::Method(hir::MethodSig {
ref decl, ..
}, ..), ..
}) = parent {
decl.clone().and_then(|decl| {
Some((decl, false))
@ -4275,11 +4284,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
blk_id: ast::NodeId) {
self.suggest_missing_semicolon(err, expression, expected, cause_span);
if let Some((fn_decl, is_main)) = self.get_fn_decl(blk_id) {
// `fn main()` must return `()`, do not suggest changing return type
if !is_main {
self.suggest_missing_return_type(err, &fn_decl, found);
}
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);
}
}
@ -4335,20 +4341,37 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
fn suggest_missing_return_type(&self,
err: &mut DiagnosticBuilder<'tcx>,
fn_decl: &hir::FnDecl,
ty: Ty<'tcx>) {
// Only recommend changing the return type for methods that
expected: Ty<'tcx>,
found: Ty<'tcx>,
can_suggest: 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).
if let &hir::FnDecl {
output: hir::FunctionRetTy::DefaultReturn(span), ..
} = fn_decl {
if ty.is_suggestable() {
match (&fn_decl.output, found.is_suggestable(), can_suggest) {
(&hir::FunctionRetTy::DefaultReturn(span), true, true) => {
err.span_suggestion(span,
"try adding a return type",
format!("-> {} ", ty));
} else {
format!("-> {} ", found));
}
(&hir::FunctionRetTy::DefaultReturn(span), false, true) => {
err.span_label(span, "possibly return type missing here?");
}
(&hir::FunctionRetTy::DefaultReturn(span), _, _) => {
// `fn main()` must return `()`, do not suggest changing return type
err.span_label(span, "expected `()` because of default return type");
}
(&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.
debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.node);
let sp = ty.span;
let ty = AstConv::ast_ty_to_ty(self, ty);
debug!("suggest_missing_return_type: return type sty {:?}", ty.sty);
debug!("suggest_missing_return_type: expected type sty {:?}", ty.sty);
if ty.sty == expected.sty {
err.span_label(sp, format!("expected `{}` because of return type",
expected));
}
}
}
}

View File

@ -20,17 +20,15 @@ impl Bar for Foo<i32> {
}
impl<T> Foo<T> {
fn new<U>(u: U) -> Foo<U> {
fn new<U>(u: U) -> Foo<U> { //~ NOTE expected `Foo<U>` because of return type
Self {
//~^ ERROR mismatched types
//~| expected type parameter, found a different type parameter
//~| expected type `Foo<U>`
//~| found type `Foo<T>`
//~| NOTE expected type parameter, found a different type parameter
//~| NOTE expected type `Foo<U>`
inner: u
//~^ ERROR mismatched types
//~| expected type parameter, found a different type parameter
//~| expected type `T`
//~| found type `U`
//~| NOTE expected type parameter, found a different type parameter
//~| NOTE expected type `T`
}
}
}

View File

@ -1,6 +1,8 @@
error[E0308]: mismatched types
--> $DIR/block-must-not-have-result-res.rs:15:9
|
14 | fn drop(&mut self) {
| - expected `()` because of default return type
15 | true //~ ERROR mismatched types
| ^^^^ expected (), found bool
|

View File

@ -1,6 +1,8 @@
error[E0308]: mismatched types
--> $DIR/issue-13624.rs:17:5
|
16 | pub fn get_enum_struct_variant() -> () {
| -- expected `()` because of return type
17 | Enum::EnumStructVariant { x: 1, y: 2, z: 3 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found enum `a::Enum`
|

View File

@ -11,6 +11,9 @@ error[E0277]: the trait bound `{integer}: Scalar` is not satisfied
error[E0308]: mismatched types
--> $DIR/issue-22645.rs:25:3
|
23 | fn main() {
| - expected `()` because of default return type
24 | let b = Bob + 3.5;
25 | b + 3 //~ ERROR E0277
| ^^^^^ expected (), found struct `Bob`
|

View File

@ -1,6 +1,8 @@
error[E0308]: mismatched types
--> $DIR/issue-5500.rs:12:5
|
11 | fn main() {
| - expected `()` because of default return type
12 | &panic!()
| ^^^^^^^^^ expected (), found reference
|

View File

@ -1,6 +1,8 @@
error[E0308]: mismatched types
--> $DIR/abridged.rs:26:5
|
25 | fn a() -> Foo {
| --- expected `Foo` because of return type
26 | Some(Foo { bar: 1 })
| ^^^^^^^^^^^^^^^^^^^^ expected struct `Foo`, found enum `std::option::Option`
|
@ -10,6 +12,8 @@ error[E0308]: mismatched types
error[E0308]: mismatched types
--> $DIR/abridged.rs:30:5
|
29 | fn a2() -> Foo {
| --- expected `Foo` because of return type
30 | Ok(Foo { bar: 1})
| ^^^^^^^^^^^^^^^^^ expected struct `Foo`, found enum `std::result::Result`
|
@ -19,6 +23,8 @@ error[E0308]: mismatched types
error[E0308]: mismatched types
--> $DIR/abridged.rs:34:5
|
33 | fn b() -> Option<Foo> {
| ----------- expected `std::option::Option<Foo>` because of return type
34 | Foo { bar: 1 }
| ^^^^^^^^^^^^^^ expected enum `std::option::Option`, found struct `Foo`
|
@ -28,6 +34,8 @@ error[E0308]: mismatched types
error[E0308]: mismatched types
--> $DIR/abridged.rs:38:5
|
37 | fn c() -> Result<Foo, Bar> {
| ---------------- expected `std::result::Result<Foo, Bar>` because of return type
38 | Foo { bar: 1 }
| ^^^^^^^^^^^^^^ expected enum `std::result::Result`, found struct `Foo`
|
@ -37,6 +45,9 @@ error[E0308]: mismatched types
error[E0308]: mismatched types
--> $DIR/abridged.rs:49:5
|
41 | fn d() -> X<X<String, String>, String> {
| ---------------------------- expected `X<X<std::string::String, std::string::String>, std::string::String>` because of return type
...
49 | x
| ^ expected struct `std::string::String`, found integral variable
|
@ -46,6 +57,9 @@ error[E0308]: mismatched types
error[E0308]: mismatched types
--> $DIR/abridged.rs:60:5
|
52 | fn e() -> X<X<String, String>, String> {
| ---------------------------- expected `X<X<std::string::String, std::string::String>, std::string::String>` because of return type
...
60 | x
| ^ expected struct `std::string::String`, found integral variable
|