Skip to content

Commit 1a96f31

Browse files
authored
Rollup merge of #100130 - compiler-errors:erroneous-return-span, r=lcnr
Avoid pointing out `return` span if it has nothing to do with type error This code: ```rust fn f(_: String) {} fn main() { let x = || { if true { return (); } f(""); }; } ``` Emits this: ``` Compiling playground v0.0.1 (/playground) error[E0308]: mismatched types --> src/main.rs:8:11 | 8 | f(""); | ^^- help: try using a conversion method: `.to_string()` | | | expected struct `String`, found `&str` | note: return type inferred to be `String` here --> src/main.rs:6:20 | 6 | return (); | ^^ ``` Specifically, that note has nothing to do with the type error in question. This is because the change implemented in #84244 tries to point out the `return` span on _any_ type coercion error within a closure that happens after a `return` statement, regardless of if the error has anything to do with it. This is really easy to trigger -- just needs a closure (or an `async`) and an early return (or any other form, e.g. `?` operator suffices) -- and super distracting in production codebases. I'm letting #84128 regress because that issue is much harder to fix correctly, and I can re-open that issue after this lands. As a drive-by, I added a `resolve_vars_if_possible` to the coercion error logic, which leads to some error improvements. Unrelated to the issue above, though.
2 parents 879c17f + 1f463ac commit 1a96f31

14 files changed

+159
-38
lines changed

compiler/rustc_typeck/src/check/coercion.rs

+23-1
Original file line numberDiff line numberDiff line change
@@ -1493,6 +1493,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
14931493
// type)
14941494
(self.final_ty.unwrap_or(self.expected_ty), expression_ty)
14951495
};
1496+
let (expected, found) = fcx.resolve_vars_if_possible((expected, found));
14961497

14971498
let mut err;
14981499
let mut unsized_return = false;
@@ -1695,9 +1696,30 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
16951696
);
16961697
}
16971698

1698-
if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.get(), fn_output) {
1699+
let ret_coercion_span = fcx.ret_coercion_span.get();
1700+
1701+
if let Some(sp) = ret_coercion_span
1702+
// If the closure has an explicit return type annotation, or if
1703+
// the closure's return type has been inferred from outside
1704+
// requirements (such as an Fn* trait bound), then a type error
1705+
// may occur at the first return expression we see in the closure
1706+
// (if it conflicts with the declared return type). Skip adding a
1707+
// note in this case, since it would be incorrect.
1708+
&& !fcx.return_type_pre_known
1709+
{
1710+
err.span_note(
1711+
sp,
1712+
&format!(
1713+
"return type inferred to be `{}` here",
1714+
expected
1715+
),
1716+
);
1717+
}
1718+
1719+
if let (Some(sp), Some(fn_output)) = (ret_coercion_span, fn_output) {
16991720
self.add_impl_trait_explanation(&mut err, cause, fcx, expected, sp, fn_output);
17001721
}
1722+
17011723
err
17021724
}
17031725

compiler/rustc_typeck/src/check/demand.rs

-22
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
4545
self.note_type_is_not_clone(err, expected, expr_ty, expr);
4646
self.note_need_for_fn_pointer(err, expected, expr_ty);
4747
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
48-
self.report_closure_inferred_return_type(err, expected);
4948
}
5049

5150
// Requires that the two types unify, and prints an error message if
@@ -1418,25 +1417,4 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14181417
_ => false,
14191418
}
14201419
}
1421-
1422-
// Report the type inferred by the return statement.
1423-
fn report_closure_inferred_return_type(&self, err: &mut Diagnostic, expected: Ty<'tcx>) {
1424-
if let Some(sp) = self.ret_coercion_span.get()
1425-
// If the closure has an explicit return type annotation, or if
1426-
// the closure's return type has been inferred from outside
1427-
// requirements (such as an Fn* trait bound), then a type error
1428-
// may occur at the first return expression we see in the closure
1429-
// (if it conflicts with the declared return type). Skip adding a
1430-
// note in this case, since it would be incorrect.
1431-
&& !self.return_type_pre_known
1432-
{
1433-
err.span_note(
1434-
sp,
1435-
&format!(
1436-
"return type inferred to be `{}` here",
1437-
self.resolve_vars_if_possible(expected)
1438-
),
1439-
);
1440-
}
1441-
}
14421420
}

src/test/ui/closures/issue-84128.stderr

-5
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,6 @@ LL | Foo(())
66
| |
77
| arguments to this struct are incorrect
88
|
9-
note: return type inferred to be `{integer}` here
10-
--> $DIR/issue-84128.rs:10:20
11-
|
12-
LL | return Foo(0);
13-
| ^^^^^^
149
note: tuple struct defined here
1510
--> $DIR/issue-84128.rs:5:8
1611
|

src/test/ui/expr/if/if-branch-types.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ LL | let x = if true { 10i32 } else { 10u32 };
55
| ----- ^^^^^ expected `i32`, found `u32`
66
| |
77
| expected because of this
8+
|
9+
help: change the type of the numeric literal from `u32` to `i32`
10+
|
11+
LL | let x = if true { 10i32 } else { 10i32 };
12+
| ~~~
813

914
error: aborting due to previous error
1015

src/test/ui/expr/if/if-else-type-mismatch.stderr

+10
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ LL | | 2u32
1010
| | ^^^^ expected `i32`, found `u32`
1111
LL | | };
1212
| |_____- `if` and `else` have incompatible types
13+
|
14+
help: change the type of the numeric literal from `u32` to `i32`
15+
|
16+
LL | 2i32
17+
| ~~~
1318

1419
error[E0308]: `if` and `else` have incompatible types
1520
--> $DIR/if-else-type-mismatch.rs:8:38
@@ -18,6 +23,11 @@ LL | let _ = if true { 42i32 } else { 42u32 };
1823
| ----- ^^^^^ expected `i32`, found `u32`
1924
| |
2025
| expected because of this
26+
|
27+
help: change the type of the numeric literal from `u32` to `i32`
28+
|
29+
LL | let _ = if true { 42i32 } else { 42i32 };
30+
| ~~~
2131

2232
error[E0308]: `if` and `else` have incompatible types
2333
--> $DIR/if-else-type-mismatch.rs:13:9

src/test/ui/generator/type-mismatch-signature-deduction.stderr

+6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ note: return type inferred to be `Result<{integer}, _>` here
1111
|
1212
LL | return Ok(6);
1313
| ^^^^^
14+
help: try wrapping the expression in a variant of `Result`
15+
|
16+
LL | Ok(5)
17+
| +++ +
18+
LL | Err(5)
19+
| ++++ +
1420

1521
error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:7:5: 7:7] as Generator>::Return == i32`
1622
--> $DIR/type-mismatch-signature-deduction.rs:5:13

src/test/ui/impl-trait/equality.stderr

+6-1
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,15 @@ error[E0308]: mismatched types
1212
--> $DIR/equality.rs:15:5
1313
|
1414
LL | fn two(x: bool) -> impl Foo {
15-
| -------- expected `_` because of return type
15+
| -------- expected `i32` because of return type
1616
...
1717
LL | 0_u32
1818
| ^^^^^ expected `i32`, found `u32`
19+
|
20+
help: change the type of the numeric literal from `u32` to `i32`
21+
|
22+
LL | 0_i32
23+
| ~~~
1924

2025
error[E0277]: cannot add `impl Foo` to `u32`
2126
--> $DIR/equality.rs:24:11

src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
22
--> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:36:5
33
|
44
LL | fn can() -> impl NotObjectSafe {
5-
| ------------------ expected `_` because of return type
5+
| ------------------ expected `A` because of return type
66
...
77
LL | B
88
| ^ expected struct `A`, found struct `B`
@@ -11,7 +11,7 @@ error[E0308]: mismatched types
1111
--> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:43:5
1212
|
1313
LL | fn cat() -> impl ObjectSafe {
14-
| --------------- expected `_` because of return type
14+
| --------------- expected `A` because of return type
1515
...
1616
LL | B
1717
| ^ expected struct `A`, found struct `B`

src/test/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr

+61-6
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,43 @@ error[E0308]: mismatched types
22
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:5:5
33
|
44
LL | fn foo() -> impl std::fmt::Display {
5-
| ---------------------- expected `_` because of return type
5+
| ---------------------- expected `i32` because of return type
66
...
77
LL | 1u32
88
| ^^^^ expected `i32`, found `u32`
9+
|
10+
help: change the type of the numeric literal from `u32` to `i32`
11+
|
12+
LL | 1i32
13+
| ~~~
914

1015
error[E0308]: mismatched types
1116
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:12:16
1217
|
1318
LL | fn bar() -> impl std::fmt::Display {
14-
| ---------------------- expected `_` because of return type
19+
| ---------------------- expected `i32` because of return type
1520
...
1621
LL | return 1u32;
1722
| ^^^^ expected `i32`, found `u32`
23+
|
24+
help: change the type of the numeric literal from `u32` to `i32`
25+
|
26+
LL | return 1i32;
27+
| ~~~
1828

1929
error[E0308]: mismatched types
2030
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:20:9
2131
|
2232
LL | fn baz() -> impl std::fmt::Display {
23-
| ---------------------- expected `_` because of return type
33+
| ---------------------- expected `i32` because of return type
2434
...
2535
LL | 1u32
2636
| ^^^^ expected `i32`, found `u32`
37+
|
38+
help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
39+
|
40+
LL | }.try_into().unwrap()
41+
| ++++++++++++++++++++
2742

2843
error[E0308]: `if` and `else` have incompatible types
2944
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:28:9
@@ -36,36 +51,56 @@ LL | | 1u32
3651
| | ^^^^ expected `i32`, found `u32`
3752
LL | | }
3853
| |_____- `if` and `else` have incompatible types
54+
|
55+
help: change the type of the numeric literal from `u32` to `i32`
56+
|
57+
LL | 1i32
58+
| ~~~
3959

4060
error[E0308]: mismatched types
4161
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:35:14
4262
|
4363
LL | fn bat() -> impl std::fmt::Display {
44-
| ---------------------- expected `_` because of return type
64+
| ---------------------- expected `i32` because of return type
4565
...
4666
LL | _ => 1u32,
4767
| ^^^^ expected `i32`, found `u32`
68+
|
69+
help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
70+
|
71+
LL | }.try_into().unwrap()
72+
| ++++++++++++++++++++
4873

4974
error[E0308]: mismatched types
5075
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:40:5
5176
|
5277
LL | fn can() -> impl std::fmt::Display {
53-
| ---------------------- expected `_` because of return type
78+
| ---------------------- expected `i32` because of return type
5479
LL | / match 13 {
5580
LL | | 0 => return 0i32,
5681
LL | | 1 => 1u32,
5782
LL | | _ => 2u32,
5883
LL | | }
5984
| |_____^ expected `i32`, found `u32`
85+
|
86+
help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
87+
|
88+
LL | }.try_into().unwrap()
89+
| ++++++++++++++++++++
6090

6191
error[E0308]: mismatched types
6292
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:53:13
6393
|
6494
LL | fn cat() -> impl std::fmt::Display {
65-
| ---------------------- expected `_` because of return type
95+
| ---------------------- expected `i32` because of return type
6696
...
6797
LL | 1u32
6898
| ^^^^ expected `i32`, found `u32`
99+
|
100+
help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
101+
|
102+
LL | }.try_into().unwrap()
103+
| ++++++++++++++++++++
69104

70105
error[E0308]: `match` arms have incompatible types
71106
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:61:14
@@ -78,6 +113,11 @@ LL | | 1 => 1u32,
78113
LL | | _ => 2u32,
79114
LL | | }
80115
| |_____- `match` arms have incompatible types
116+
|
117+
help: change the type of the numeric literal from `u32` to `i32`
118+
|
119+
LL | 1 => 1i32,
120+
| ~~~
81121

82122
error[E0308]: `if` and `else` have incompatible types
83123
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:97:9
@@ -90,6 +130,11 @@ LL | | 1u32
90130
| | ^^^^ expected `i32`, found `u32`
91131
LL | | }
92132
| |_____- `if` and `else` have incompatible types
133+
|
134+
help: change the type of the numeric literal from `u32` to `i32`
135+
|
136+
LL | 1i32
137+
| ~~~
93138

94139
error[E0746]: return type cannot have an unboxed trait object
95140
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:66:13
@@ -125,6 +170,11 @@ LL | | 1 => 1u32,
125170
LL | | _ => 2u32,
126171
LL | | }
127172
| |_____- `match` arms have incompatible types
173+
|
174+
help: change the type of the numeric literal from `u32` to `i32`
175+
|
176+
LL | 1 => 1i32,
177+
| ~~~
128178

129179
error[E0746]: return type cannot have an unboxed trait object
130180
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:77:13
@@ -164,6 +214,11 @@ LL | | 1u32
164214
| | ^^^^ expected `i32`, found `u32`
165215
LL | | }
166216
| |_____- `if` and `else` have incompatible types
217+
|
218+
help: change the type of the numeric literal from `u32` to `i32`
219+
|
220+
LL | 1i32
221+
| ~~~
167222

168223
error[E0746]: return type cannot have an unboxed trait object
169224
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:85:13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// edition:2021
2+
3+
async fn f(_: &()) {}
4+
//~^ NOTE function defined here
5+
//~| NOTE
6+
// Second note is the span of the underlined argument, I think...
7+
8+
fn main() {
9+
(|| async {
10+
Err::<(), ()>(())?;
11+
f(());
12+
//~^ ERROR mismatched types
13+
//~| NOTE arguments to this function are incorrect
14+
//~| NOTE expected `&()`, found `()`
15+
//~| HELP consider borrowing here
16+
Ok::<(), ()>(())
17+
})();
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/dont-point-return-on-E0308.rs:11:11
3+
|
4+
LL | f(());
5+
| - ^^
6+
| | |
7+
| | expected `&()`, found `()`
8+
| | help: consider borrowing here: `&()`
9+
| arguments to this function are incorrect
10+
|
11+
note: function defined here
12+
--> $DIR/dont-point-return-on-E0308.rs:3:10
13+
|
14+
LL | async fn f(_: &()) {}
15+
| ^ ------
16+
17+
error: aborting due to previous error
18+
19+
For more information about this error, try `rustc --explain E0308`.

src/test/ui/mismatched_types/issue-84976.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ error[E0308]: mismatched types
33
|
44
LL | length = { foo(&length) };
55
| ^^^^^^^^^^^^ expected `u32`, found `i32`
6+
|
7+
help: you can convert an `i32` to a `u32` and panic if the converted value doesn't fit
8+
|
9+
LL | length = { foo(&length).try_into().unwrap() };
10+
| ++++++++++++++++++++
611

712
error[E0308]: mismatched types
813
--> $DIR/issue-84976.rs:17:14

src/test/ui/reify-intrinsic.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ LL | std::intrinsics::unlikely,
2323
|
2424
= note: expected fn item `extern "rust-intrinsic" fn(_) -> _ {likely}`
2525
found fn item `extern "rust-intrinsic" fn(_) -> _ {unlikely}`
26+
= note: different `fn` items always have unique types, even if their signatures are the same
27+
= help: change the expected type to be function pointer `extern "rust-intrinsic" fn(bool) -> bool`
28+
= help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `likely as extern "rust-intrinsic" fn(bool) -> bool`
2629

2730
error: aborting due to 3 previous errors
2831

src/test/ui/type-alias-impl-trait/issue-74280.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
22
--> $DIR/issue-74280.rs:9:5
33
|
44
LL | fn test() -> Test {
5-
| ---- expected `_` because of return type
5+
| ---- expected `()` because of return type
66
LL | let y = || -> Test { () };
77
LL | 7
88
| ^ expected `()`, found integer

0 commit comments

Comments
 (0)