Skip to content

Commit 5b9e02a

Browse files
authored
Rollup merge of #57723 - estebank:fix, r=davidtwco
Point at cause for expectation in return type type error Various improvements and fixes for type errors in return expressions. Fix #57664.
2 parents 3bc61cd + 2e06d9c commit 5b9e02a

13 files changed

+201
-19
lines changed

src/librustc_typeck/check/coercion.rs

+37-5
Original file line numberDiff line numberDiff line change
@@ -1216,28 +1216,60 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E>
12161216
"supposed to be part of a block tail expression, but the \
12171217
expression is empty");
12181218
});
1219-
fcx.suggest_mismatched_types_on_tail(
1219+
let pointing_at_return_type = fcx.suggest_mismatched_types_on_tail(
12201220
&mut db,
12211221
expr,
12221222
expected,
12231223
found,
12241224
cause.span,
12251225
blk_id,
12261226
);
1227-
if let Some(sp) = fcx.ret_coercion_span.borrow().as_ref() {
1228-
if !sp.overlaps(cause.span) {
1227+
// FIXME: replace with navigating up the chain until hitting an fn or
1228+
// bailing if no "pass-through" Node is found, in order to provide a
1229+
// suggestion when encountering something like:
1230+
// ```
1231+
// fn foo(a: bool) -> impl Debug {
1232+
// if a {
1233+
// bar()?;
1234+
// }
1235+
// {
1236+
// let x = unsafe { bar() };
1237+
// x
1238+
// }
1239+
// }
1240+
// ```
1241+
//
1242+
// Verify that this is a tail expression of a function, otherwise the
1243+
// label pointing out the cause for the type coercion will be wrong
1244+
// as prior return coercions would not be relevant (#57664).
1245+
let parent_id = fcx.tcx.hir().get_parent_node(blk_id);
1246+
let parent = fcx.tcx.hir().get(fcx.tcx.hir().get_parent_node(parent_id));
1247+
if fcx.get_node_fn_decl(parent).is_some() && !pointing_at_return_type {
1248+
if let Some(sp) = fcx.ret_coercion_span.borrow().as_ref() {
12291249
db.span_label(*sp, reason_label);
12301250
}
12311251
}
12321252
}
1233-
_ => {
1253+
ObligationCauseCode::ReturnType(_id) => {
12341254
db = fcx.report_mismatched_types(cause, expected, found, err);
1235-
if let Some(sp) = fcx.ret_coercion_span.borrow().as_ref() {
1255+
let _id = fcx.tcx.hir().get_parent_node(_id);
1256+
let mut pointing_at_return_type = false;
1257+
if let Some((fn_decl, can_suggest)) = fcx.get_fn_decl(_id) {
1258+
pointing_at_return_type = fcx.suggest_missing_return_type(
1259+
&mut db, &fn_decl, expected, found, can_suggest);
1260+
}
1261+
if let (Some(sp), false) = (
1262+
fcx.ret_coercion_span.borrow().as_ref(),
1263+
pointing_at_return_type,
1264+
) {
12361265
if !sp.overlaps(cause.span) {
12371266
db.span_label(*sp, reason_label);
12381267
}
12391268
}
12401269
}
1270+
_ => {
1271+
db = fcx.report_mismatched_types(cause, expected, found, err);
1272+
}
12411273
}
12421274

12431275
if let Some(augment_error) = augment_error {

src/librustc_typeck/check/mod.rs

+25-11
Original file line numberDiff line numberDiff line change
@@ -4347,11 +4347,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
43474347
struct_span_err!(self.tcx.sess, expr.span, E0572,
43484348
"return statement outside of function body").emit();
43494349
} else if let Some(ref e) = *expr_opt {
4350-
*self.ret_coercion_span.borrow_mut() = Some(e.span);
4350+
if self.ret_coercion_span.borrow().is_none() {
4351+
*self.ret_coercion_span.borrow_mut() = Some(e.span);
4352+
}
43514353
self.check_return_expr(e);
43524354
} else {
43534355
let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut();
4354-
*self.ret_coercion_span.borrow_mut() = Some(expr.span);
4356+
if self.ret_coercion_span.borrow().is_none() {
4357+
*self.ret_coercion_span.borrow_mut() = Some(expr.span);
4358+
}
43554359
let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression);
43564360
if let Some((fn_decl, _)) = self.get_fn_decl(expr.id) {
43574361
coercion.coerce_forced_unit(
@@ -5081,12 +5085,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
50815085
found: Ty<'tcx>,
50825086
cause_span: Span,
50835087
blk_id: ast::NodeId,
5084-
) {
5088+
) -> bool {
50855089
self.suggest_missing_semicolon(err, expression, expected, cause_span);
5090+
let mut pointing_at_return_type = false;
50865091
if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
5087-
self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest);
5092+
pointing_at_return_type = self.suggest_missing_return_type(
5093+
err, &fn_decl, expected, found, can_suggest);
50885094
}
50895095
self.suggest_ref_or_into(err, expression, expected, found);
5096+
pointing_at_return_type
50905097
}
50915098

50925099
pub fn suggest_ref_or_into(
@@ -5185,12 +5192,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
51855192
/// This routine checks if the return type is left as default, the method is not part of an
51865193
/// `impl` block and that it isn't the `main` method. If so, it suggests setting the return
51875194
/// type.
5188-
fn suggest_missing_return_type(&self,
5189-
err: &mut DiagnosticBuilder<'tcx>,
5190-
fn_decl: &hir::FnDecl,
5191-
expected: Ty<'tcx>,
5192-
found: Ty<'tcx>,
5193-
can_suggest: bool) {
5195+
fn suggest_missing_return_type(
5196+
&self,
5197+
err: &mut DiagnosticBuilder<'tcx>,
5198+
fn_decl: &hir::FnDecl,
5199+
expected: Ty<'tcx>,
5200+
found: Ty<'tcx>,
5201+
can_suggest: bool,
5202+
) -> bool {
51945203
// Only suggest changing the return type for methods that
51955204
// haven't set a return type at all (and aren't `fn main()` or an impl).
51965205
match (&fn_decl.output, found.is_suggestable(), can_suggest, expected.is_unit()) {
@@ -5200,16 +5209,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
52005209
"try adding a return type",
52015210
format!("-> {} ", self.resolve_type_vars_with_obligations(found)),
52025211
Applicability::MachineApplicable);
5212+
true
52035213
}
52045214
(&hir::FunctionRetTy::DefaultReturn(span), false, true, true) => {
52055215
err.span_label(span, "possibly return type missing here?");
5216+
true
52065217
}
52075218
(&hir::FunctionRetTy::DefaultReturn(span), _, false, true) => {
52085219
// `fn main()` must return `()`, do not suggest changing return type
52095220
err.span_label(span, "expected `()` because of default return type");
5221+
true
52105222
}
52115223
// expectation was caused by something else, not the default return
5212-
(&hir::FunctionRetTy::DefaultReturn(_), _, _, false) => {}
5224+
(&hir::FunctionRetTy::DefaultReturn(_), _, _, false) => false,
52135225
(&hir::FunctionRetTy::Return(ref ty), _, _, _) => {
52145226
// Only point to return type if the expected type is the return type, as if they
52155227
// are not, the expectation must have been caused by something else.
@@ -5221,7 +5233,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
52215233
if ty.sty == expected.sty {
52225234
err.span_label(sp, format!("expected `{}` because of return type",
52235235
expected));
5236+
return true;
52245237
}
5238+
false
52255239
}
52265240
}
52275241
}

src/test/ui/fully-qualified-type/fully-qualified-type-name2.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
error[E0308]: mismatched types
22
--> $DIR/fully-qualified-type-name2.rs:12:12
33
|
4+
LL | fn bar(x: x::Foo) -> y::Foo {
5+
| ------ expected `y::Foo` because of return type
46
LL | return x;
57
| ^ expected enum `y::Foo`, found enum `x::Foo`
68
|

src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
error[E0308]: mismatched types
22
--> $DIR/fully-qualified-type-name4.rs:6:12
33
|
4+
LL | fn bar(x: usize) -> Option<usize> {
5+
| ------------- expected `std::option::Option<usize>` because of return type
46
LL | return x;
57
| ^ expected enum `std::option::Option`, found usize
68
|

src/test/ui/liveness/liveness-forgot-ret.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
22
--> $DIR/liveness-forgot-ret.rs:3:19
33
|
44
LL | fn f(a: isize) -> isize { if god_exists(a) { return 5; }; }
5-
| - ^^^^^ expected isize, found () - expected because of this statement
5+
| - ^^^^^ expected isize, found ()
66
| |
77
| this function's body doesn't return
88
|
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
fn unrelated() -> Result<(), std::string::ParseError> { // #57664
2+
let x = 0;
3+
4+
match x {
5+
1 => {
6+
let property_value_as_string = "a".parse()?;
7+
}
8+
2 => {
9+
let value: &bool = unsafe { &42 };
10+
//~^ ERROR mismatched types
11+
}
12+
};
13+
14+
Ok(())
15+
}
16+
17+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/point-to-type-err-cause-on-impl-trait-return-2.rs:9:41
3+
|
4+
LL | let value: &bool = unsafe { &42 };
5+
| ^^^ expected bool, found integer
6+
|
7+
= note: expected type `&bool`
8+
found type `&{integer}`
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0308`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
fn foo() -> impl std::fmt::Display {
2+
if false {
3+
return 0i32;
4+
}
5+
1u32
6+
//~^ ERROR mismatched types
7+
}
8+
9+
fn bar() -> impl std::fmt::Display {
10+
if false {
11+
return 0i32;
12+
} else {
13+
return 1u32;
14+
//~^ ERROR mismatched types
15+
}
16+
}
17+
18+
fn baz() -> impl std::fmt::Display {
19+
if false {
20+
//~^ ERROR mismatched types
21+
return 0i32;
22+
} else {
23+
1u32
24+
}
25+
}
26+
27+
fn qux() -> impl std::fmt::Display {
28+
if false {
29+
0i32
30+
} else {
31+
1u32
32+
//~^ ERROR if and else have incompatible types
33+
}
34+
}
35+
36+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:5:5
3+
|
4+
LL | return 0i32;
5+
| ---- expected because of this statement
6+
LL | }
7+
LL | 1u32
8+
| ^^^^ expected i32, found u32
9+
|
10+
= note: expected type `i32`
11+
found type `u32`
12+
13+
error[E0308]: mismatched types
14+
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:13:16
15+
|
16+
LL | return 0i32;
17+
| ---- expected because of this statement
18+
LL | } else {
19+
LL | return 1u32;
20+
| ^^^^ expected i32, found u32
21+
|
22+
= note: expected type `i32`
23+
found type `u32`
24+
25+
error[E0308]: mismatched types
26+
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:19:5
27+
|
28+
LL | / if false {
29+
LL | | //~^ ERROR mismatched types
30+
LL | | return 0i32;
31+
| | ---- expected because of this statement
32+
LL | | } else {
33+
LL | | 1u32
34+
LL | | }
35+
| |_____^ expected i32, found u32
36+
|
37+
= note: expected type `i32`
38+
found type `u32`
39+
40+
error[E0308]: if and else have incompatible types
41+
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:31:9
42+
|
43+
LL | / if false {
44+
LL | | 0i32
45+
| | ---- expected because of this
46+
LL | | } else {
47+
LL | | 1u32
48+
| | ^^^^ expected i32, found u32
49+
LL | | //~^ ERROR if and else have incompatible types
50+
LL | | }
51+
| |_____- if and else have incompatible types
52+
|
53+
= note: expected type `i32`
54+
found type `u32`
55+
56+
error: aborting due to 4 previous errors
57+
58+
For more information about this error, try `rustc --explain E0308`.

src/test/ui/proc-macro/span-preservation.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ LL | let x: usize = "hello";;;;; //~ ERROR mismatched types
1515
error[E0308]: mismatched types
1616
--> $DIR/span-preservation.rs:19:29
1717
|
18+
LL | fn b(x: Option<isize>) -> usize {
19+
| ----- expected `usize` because of return type
20+
LL | match x {
1821
LL | Some(x) => { return x }, //~ ERROR mismatched types
1922
| ^ expected usize, found isize
2023

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

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
error[E0308]: mismatched types
22
--> $DIR/return-from-diverging.rs:4:12
33
|
4+
LL | fn fail() -> ! {
5+
| - expected `!` because of return type
46
LL | return "wow"; //~ ERROR mismatched types
57
| ^^^^^ expected !, found reference
68
|

src/test/ui/tail-typeck.stderr

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
22
--> $DIR/tail-typeck.rs:3:26
33
|
44
LL | fn f() -> isize { return g(); }
5-
| ^^^ expected isize, found usize
5+
| ----- ^^^ expected isize, found usize
6+
| |
7+
| expected `isize` because of return type
68

79
error: aborting due to previous error
810

src/test/ui/wrong-ret-type.stderr

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
22
--> $DIR/wrong-ret-type.rs:2:49
33
|
44
LL | fn mk_int() -> usize { let i: isize = 3; return i; }
5-
| ^ expected usize, found isize
5+
| ----- ^ expected usize, found isize
6+
| |
7+
| expected `usize` because of return type
68

79
error: aborting due to previous error
810

0 commit comments

Comments
 (0)