Skip to content

Commit d96f9d4

Browse files
committed
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 rust-lang#42850, fixes rust-lang#25133, fixes rust-lang#41897.
1 parent b5e8a8e commit d96f9d4

File tree

10 files changed

+68
-26
lines changed

10 files changed

+68
-26
lines changed

src/librustc/hir/map/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -664,7 +664,7 @@ impl<'hir> Map<'hir> {
664664
match *node {
665665
NodeExpr(ref expr) => {
666666
match expr.node {
667-
ExprWhile(..) | ExprLoop(..) => true,
667+
ExprWhile(..) | ExprLoop(..) | ExprIf(..) => true,
668668
_ => false,
669669
}
670670
}

src/librustc/ty/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,7 @@ impl<'tcx> TyS<'tcx> {
488488
TypeVariants::TyFnPtr(..) |
489489
TypeVariants::TyDynamic(..) |
490490
TypeVariants::TyClosure(..) |
491+
TypeVariants::TyInfer(..) |
491492
TypeVariants::TyProjection(..) => false,
492493
_ => true,
493494
}

src/librustc_typeck/check/mod.rs

+35-18
Original file line numberDiff line numberDiff line change
@@ -4187,8 +4187,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
41874187
ty
41884188
}
41894189

4190-
/// Given a `NodeId`, return the `FnDecl` of the method it is enclosed by and whether it is
4191-
/// `fn main` if it is a method, `None` otherwise.
4190+
/// Given a `NodeId`, return the `FnDecl` of the method it is enclosed by and whether a
4191+
/// suggetion can be made, `None` otherwise.
41924192
pub fn get_fn_decl(&self, blk_id: ast::NodeId) -> Option<(hir::FnDecl, bool)> {
41934193
// Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
41944194
// `while` before reaching it, as block tail returns are not available in them.
@@ -4199,14 +4199,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
41994199
name, node: hir::ItemFn(ref decl, ..), ..
42004200
}) = parent {
42014201
decl.clone().and_then(|decl| {
4202-
// This is less than ideal, it will not present the return type span on any
4203-
// method called `main`, regardless of whether it is actually the entry point.
4204-
Some((decl, name == Symbol::intern("main")))
4202+
// This is less than ideal, it will not suggest a return type span on any
4203+
// method called `main`, regardless of whether it is actually the entry point,
4204+
// but it will still present it as the reason for the expected type.
4205+
Some((decl, name != Symbol::intern("main")))
42054206
})
42064207
} else if let Node::NodeTraitItem(&hir::TraitItem {
42074208
node: hir::TraitItemKind::Method(hir::MethodSig {
42084209
ref decl, ..
42094210
}, ..), ..
4211+
}) = parent {
4212+
decl.clone().and_then(|decl| {
4213+
Some((decl, true))
4214+
})
4215+
} else if let Node::NodeImplItem(&hir::ImplItem {
4216+
node: hir::ImplItemKind::Method(hir::MethodSig {
4217+
ref decl, ..
4218+
}, ..), ..
42104219
}) = parent {
42114220
decl.clone().and_then(|decl| {
42124221
Some((decl, false))
@@ -4233,11 +4242,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
42334242
blk_id: ast::NodeId) {
42344243
self.suggest_missing_semicolon(err, expression, expected, cause_span);
42354244

4236-
if let Some((fn_decl, is_main)) = self.get_fn_decl(blk_id) {
4237-
// `fn main()` must return `()`, do not suggest changing return type
4238-
if !is_main {
4239-
self.suggest_missing_return_type(err, &fn_decl, found);
4240-
}
4245+
if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
4246+
self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest);
42414247
}
42424248
}
42434249

@@ -4293,20 +4299,31 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
42934299
fn suggest_missing_return_type(&self,
42944300
err: &mut DiagnosticBuilder<'tcx>,
42954301
fn_decl: &hir::FnDecl,
4296-
ty: Ty<'tcx>) {
4302+
expected: Ty<'tcx>,
4303+
found: Ty<'tcx>,
4304+
can_suggest: bool) {
42974305

4298-
// Only recommend changing the return type for methods that
4306+
// Only suggest changing the return type for methods that
42994307
// haven't set a return type at all (and aren't `fn main()` or an impl).
4300-
if let &hir::FnDecl {
4301-
output: hir::FunctionRetTy::DefaultReturn(span), ..
4302-
} = fn_decl {
4303-
if ty.is_suggestable() {
4308+
match (&fn_decl.output, found.is_suggestable(), can_suggest) {
4309+
(&hir::FunctionRetTy::DefaultReturn(span), true, true) => {
43044310
err.span_suggestion(span,
43054311
"try adding a return type",
4306-
format!("-> {} ", ty));
4307-
} else {
4312+
format!("-> {} ", found));
4313+
}
4314+
(&hir::FunctionRetTy::DefaultReturn(span), false, true) => {
43084315
err.span_label(span, "possibly return type missing here?");
43094316
}
4317+
(&hir::FunctionRetTy::DefaultReturn(span), _, _) => {
4318+
// `fn main()` must return `()`, do not suggest changing return type
4319+
err.span_label(span, "expected `()` because of default return type");
4320+
}
4321+
(&hir::FunctionRetTy::Return(ref ty), _, _) => {
4322+
// Only point to return type if the expected type is the return type, as if they
4323+
// are not, the expectation must have been caused by something else.
4324+
err.span_label(ty.span,
4325+
format!("expected `{}` because of return type", expected));
4326+
}
43104327
}
43114328
}
43124329

src/test/compile-fail/struct-path-self-type-mismatch.rs

+5-7
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,15 @@ impl Bar for Foo<i32> {
2020
}
2121

2222
impl<T> Foo<T> {
23-
fn new<U>(u: U) -> Foo<U> {
23+
fn new<U>(u: U) -> Foo<U> { //~ NOTE expected `Foo<U>` because of return type
2424
Self {
2525
//~^ ERROR mismatched types
26-
//~| expected type parameter, found a different type parameter
27-
//~| expected type `Foo<U>`
28-
//~| found type `Foo<T>`
26+
//~| NOTE expected type parameter, found a different type parameter
27+
//~| NOTE expected type `Foo<U>`
2928
inner: u
3029
//~^ ERROR mismatched types
31-
//~| expected type parameter, found a different type parameter
32-
//~| expected type `T`
33-
//~| found type `U`
30+
//~| NOTE expected type parameter, found a different type parameter
31+
//~| NOTE expected type `T`
3432
}
3533
}
3634
}

src/test/ui/block-result/block-must-not-have-result-res.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
error[E0308]: mismatched types
22
--> $DIR/block-must-not-have-result-res.rs:15:9
33
|
4+
14 | fn drop(&mut self) {
5+
| - expected `()` because of default return type
46
15 | true //~ ERROR mismatched types
57
| ^^^^ expected (), found bool
68
|

src/test/ui/block-result/issue-13624.stderr

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

src/test/ui/block-result/issue-22645.stderr

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

src/test/ui/block-result/issue-5500.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
error[E0308]: mismatched types
22
--> $DIR/issue-5500.rs:12:5
33
|
4+
11 | fn main() {
5+
| - expected `()` because of default return type
46
12 | &panic!()
57
| ^^^^^^^^^ expected (), found reference
68
|

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+
21 | fn two(x: bool) -> impl Foo {
5+
| -------- expected `_` because of return type
6+
...
47
25 | 0_u32
58
| ^^^^^ expected i32, found u32
69
|

src/test/ui/mismatched_types/abridged.stderr

+14
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
error[E0308]: mismatched types
22
--> $DIR/abridged.rs:26:5
33
|
4+
25 | fn a() -> Foo {
5+
| --- expected `Foo` because of return type
46
26 | Some(Foo { bar: 1 })
57
| ^^^^^^^^^^^^^^^^^^^^ expected struct `Foo`, found enum `std::option::Option`
68
|
@@ -10,6 +12,8 @@ error[E0308]: mismatched types
1012
error[E0308]: mismatched types
1113
--> $DIR/abridged.rs:30:5
1214
|
15+
29 | fn a2() -> Foo {
16+
| --- expected `Foo` because of return type
1317
30 | Ok(Foo { bar: 1})
1418
| ^^^^^^^^^^^^^^^^^ expected struct `Foo`, found enum `std::result::Result`
1519
|
@@ -19,6 +23,8 @@ error[E0308]: mismatched types
1923
error[E0308]: mismatched types
2024
--> $DIR/abridged.rs:34:5
2125
|
26+
33 | fn b() -> Option<Foo> {
27+
| ----------- expected `std::option::Option<Foo>` because of return type
2228
34 | Foo { bar: 1 }
2329
| ^^^^^^^^^^^^^^ expected enum `std::option::Option`, found struct `Foo`
2430
|
@@ -28,6 +34,8 @@ error[E0308]: mismatched types
2834
error[E0308]: mismatched types
2935
--> $DIR/abridged.rs:38:5
3036
|
37+
37 | fn c() -> Result<Foo, Bar> {
38+
| ---------------- expected `std::result::Result<Foo, Bar>` because of return type
3139
38 | Foo { bar: 1 }
3240
| ^^^^^^^^^^^^^^ expected enum `std::result::Result`, found struct `Foo`
3341
|
@@ -37,6 +45,9 @@ error[E0308]: mismatched types
3745
error[E0308]: mismatched types
3846
--> $DIR/abridged.rs:49:5
3947
|
48+
41 | fn d() -> X<X<String, String>, String> {
49+
| ---------------------------- expected `X<X<std::string::String, std::string::String>, std::string::String>` because of return type
50+
...
4051
49 | x
4152
| ^ expected struct `std::string::String`, found integral variable
4253
|
@@ -46,6 +57,9 @@ error[E0308]: mismatched types
4657
error[E0308]: mismatched types
4758
--> $DIR/abridged.rs:60:5
4859
|
60+
52 | fn e() -> X<X<String, String>, String> {
61+
| ---------------------------- expected `X<X<std::string::String, std::string::String>, std::string::String>` because of return type
62+
...
4963
60 | x
5064
| ^ expected struct `std::string::String`, found integral variable
5165
|

0 commit comments

Comments
 (0)