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.
This commit is contained in:
Matthias Krüger 2022-08-07 01:19:33 +02:00 committed by GitHub
commit 1a96f31f76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 159 additions and 38 deletions

View File

@ -1493,6 +1493,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
// type)
(self.final_ty.unwrap_or(self.expected_ty), expression_ty)
};
let (expected, found) = fcx.resolve_vars_if_possible((expected, found));
let mut err;
let mut unsized_return = false;
@ -1695,9 +1696,30 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
);
}
if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.get(), fn_output) {
let ret_coercion_span = fcx.ret_coercion_span.get();
if let Some(sp) = ret_coercion_span
// If the closure has an explicit return type annotation, or if
// the closure's return type has been inferred from outside
// requirements (such as an Fn* trait bound), then a type error
// may occur at the first return expression we see in the closure
// (if it conflicts with the declared return type). Skip adding a
// note in this case, since it would be incorrect.
&& !fcx.return_type_pre_known
{
err.span_note(
sp,
&format!(
"return type inferred to be `{}` here",
expected
),
);
}
if let (Some(sp), Some(fn_output)) = (ret_coercion_span, fn_output) {
self.add_impl_trait_explanation(&mut err, cause, fcx, expected, sp, fn_output);
}
err
}

View File

@ -45,7 +45,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.note_type_is_not_clone(err, expected, expr_ty, expr);
self.note_need_for_fn_pointer(err, expected, expr_ty);
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
self.report_closure_inferred_return_type(err, expected);
}
// Requires that the two types unify, and prints an error message if
@ -1418,25 +1417,4 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => false,
}
}
// Report the type inferred by the return statement.
fn report_closure_inferred_return_type(&self, err: &mut Diagnostic, expected: Ty<'tcx>) {
if let Some(sp) = self.ret_coercion_span.get()
// If the closure has an explicit return type annotation, or if
// the closure's return type has been inferred from outside
// requirements (such as an Fn* trait bound), then a type error
// may occur at the first return expression we see in the closure
// (if it conflicts with the declared return type). Skip adding a
// note in this case, since it would be incorrect.
&& !self.return_type_pre_known
{
err.span_note(
sp,
&format!(
"return type inferred to be `{}` here",
self.resolve_vars_if_possible(expected)
),
);
}
}
}

View File

@ -6,11 +6,6 @@ LL | Foo(())
| |
| arguments to this struct are incorrect
|
note: return type inferred to be `{integer}` here
--> $DIR/issue-84128.rs:10:20
|
LL | return Foo(0);
| ^^^^^^
note: tuple struct defined here
--> $DIR/issue-84128.rs:5:8
|

View File

@ -5,6 +5,11 @@ LL | let x = if true { 10i32 } else { 10u32 };
| ----- ^^^^^ expected `i32`, found `u32`
| |
| expected because of this
|
help: change the type of the numeric literal from `u32` to `i32`
|
LL | let x = if true { 10i32 } else { 10i32 };
| ~~~
error: aborting due to previous error

View File

@ -10,6 +10,11 @@ LL | | 2u32
| | ^^^^ expected `i32`, found `u32`
LL | | };
| |_____- `if` and `else` have incompatible types
|
help: change the type of the numeric literal from `u32` to `i32`
|
LL | 2i32
| ~~~
error[E0308]: `if` and `else` have incompatible types
--> $DIR/if-else-type-mismatch.rs:8:38
@ -18,6 +23,11 @@ LL | let _ = if true { 42i32 } else { 42u32 };
| ----- ^^^^^ expected `i32`, found `u32`
| |
| expected because of this
|
help: change the type of the numeric literal from `u32` to `i32`
|
LL | let _ = if true { 42i32 } else { 42i32 };
| ~~~
error[E0308]: `if` and `else` have incompatible types
--> $DIR/if-else-type-mismatch.rs:13:9

View File

@ -11,6 +11,12 @@ note: return type inferred to be `Result<{integer}, _>` here
|
LL | return Ok(6);
| ^^^^^
help: try wrapping the expression in a variant of `Result`
|
LL | Ok(5)
| +++ +
LL | Err(5)
| ++++ +
error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:7:5: 7:7] as Generator>::Return == i32`
--> $DIR/type-mismatch-signature-deduction.rs:5:13

View File

@ -12,10 +12,15 @@ error[E0308]: mismatched types
--> $DIR/equality.rs:15:5
|
LL | fn two(x: bool) -> impl Foo {
| -------- expected `_` because of return type
| -------- expected `i32` because of return type
...
LL | 0_u32
| ^^^^^ expected `i32`, found `u32`
|
help: change the type of the numeric literal from `u32` to `i32`
|
LL | 0_i32
| ~~~
error[E0277]: cannot add `impl Foo` to `u32`
--> $DIR/equality.rs:24:11

View File

@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:36:5
|
LL | fn can() -> impl NotObjectSafe {
| ------------------ expected `_` because of return type
| ------------------ expected `A` because of return type
...
LL | B
| ^ expected struct `A`, found struct `B`
@ -11,7 +11,7 @@ error[E0308]: mismatched types
--> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:43:5
|
LL | fn cat() -> impl ObjectSafe {
| --------------- expected `_` because of return type
| --------------- expected `A` because of return type
...
LL | B
| ^ expected struct `A`, found struct `B`

View File

@ -2,28 +2,43 @@ error[E0308]: mismatched types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:5:5
|
LL | fn foo() -> impl std::fmt::Display {
| ---------------------- expected `_` because of return type
| ---------------------- expected `i32` because of return type
...
LL | 1u32
| ^^^^ expected `i32`, found `u32`
|
help: change the type of the numeric literal from `u32` to `i32`
|
LL | 1i32
| ~~~
error[E0308]: mismatched types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:12:16
|
LL | fn bar() -> impl std::fmt::Display {
| ---------------------- expected `_` because of return type
| ---------------------- expected `i32` because of return type
...
LL | return 1u32;
| ^^^^ expected `i32`, found `u32`
|
help: change the type of the numeric literal from `u32` to `i32`
|
LL | return 1i32;
| ~~~
error[E0308]: mismatched types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:20:9
|
LL | fn baz() -> impl std::fmt::Display {
| ---------------------- expected `_` because of return type
| ---------------------- expected `i32` because of return type
...
LL | 1u32
| ^^^^ expected `i32`, found `u32`
|
help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
|
LL | }.try_into().unwrap()
| ++++++++++++++++++++
error[E0308]: `if` and `else` have incompatible types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:28:9
@ -36,36 +51,56 @@ LL | | 1u32
| | ^^^^ expected `i32`, found `u32`
LL | | }
| |_____- `if` and `else` have incompatible types
|
help: change the type of the numeric literal from `u32` to `i32`
|
LL | 1i32
| ~~~
error[E0308]: mismatched types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:35:14
|
LL | fn bat() -> impl std::fmt::Display {
| ---------------------- expected `_` because of return type
| ---------------------- expected `i32` because of return type
...
LL | _ => 1u32,
| ^^^^ expected `i32`, found `u32`
|
help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
|
LL | }.try_into().unwrap()
| ++++++++++++++++++++
error[E0308]: mismatched types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:40:5
|
LL | fn can() -> impl std::fmt::Display {
| ---------------------- expected `_` because of return type
| ---------------------- expected `i32` because of return type
LL | / match 13 {
LL | | 0 => return 0i32,
LL | | 1 => 1u32,
LL | | _ => 2u32,
LL | | }
| |_____^ expected `i32`, found `u32`
|
help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
|
LL | }.try_into().unwrap()
| ++++++++++++++++++++
error[E0308]: mismatched types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:53:13
|
LL | fn cat() -> impl std::fmt::Display {
| ---------------------- expected `_` because of return type
| ---------------------- expected `i32` because of return type
...
LL | 1u32
| ^^^^ expected `i32`, found `u32`
|
help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
|
LL | }.try_into().unwrap()
| ++++++++++++++++++++
error[E0308]: `match` arms have incompatible types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:61:14
@ -78,6 +113,11 @@ LL | | 1 => 1u32,
LL | | _ => 2u32,
LL | | }
| |_____- `match` arms have incompatible types
|
help: change the type of the numeric literal from `u32` to `i32`
|
LL | 1 => 1i32,
| ~~~
error[E0308]: `if` and `else` have incompatible types
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:97:9
@ -90,6 +130,11 @@ LL | | 1u32
| | ^^^^ expected `i32`, found `u32`
LL | | }
| |_____- `if` and `else` have incompatible types
|
help: change the type of the numeric literal from `u32` to `i32`
|
LL | 1i32
| ~~~
error[E0746]: return type cannot have an unboxed trait object
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:66:13
@ -125,6 +170,11 @@ LL | | 1 => 1u32,
LL | | _ => 2u32,
LL | | }
| |_____- `match` arms have incompatible types
|
help: change the type of the numeric literal from `u32` to `i32`
|
LL | 1 => 1i32,
| ~~~
error[E0746]: return type cannot have an unboxed trait object
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:77:13
@ -164,6 +214,11 @@ LL | | 1u32
| | ^^^^ expected `i32`, found `u32`
LL | | }
| |_____- `if` and `else` have incompatible types
|
help: change the type of the numeric literal from `u32` to `i32`
|
LL | 1i32
| ~~~
error[E0746]: return type cannot have an unboxed trait object
--> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:85:13

View File

@ -0,0 +1,18 @@
// edition:2021
async fn f(_: &()) {}
//~^ NOTE function defined here
//~| NOTE
// Second note is the span of the underlined argument, I think...
fn main() {
(|| async {
Err::<(), ()>(())?;
f(());
//~^ ERROR mismatched types
//~| NOTE arguments to this function are incorrect
//~| NOTE expected `&()`, found `()`
//~| HELP consider borrowing here
Ok::<(), ()>(())
})();
}

View File

@ -0,0 +1,19 @@
error[E0308]: mismatched types
--> $DIR/dont-point-return-on-E0308.rs:11:11
|
LL | f(());
| - ^^
| | |
| | expected `&()`, found `()`
| | help: consider borrowing here: `&()`
| arguments to this function are incorrect
|
note: function defined here
--> $DIR/dont-point-return-on-E0308.rs:3:10
|
LL | async fn f(_: &()) {}
| ^ ------
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.

View File

@ -3,6 +3,11 @@ error[E0308]: mismatched types
|
LL | length = { foo(&length) };
| ^^^^^^^^^^^^ expected `u32`, found `i32`
|
help: you can convert an `i32` to a `u32` and panic if the converted value doesn't fit
|
LL | length = { foo(&length).try_into().unwrap() };
| ++++++++++++++++++++
error[E0308]: mismatched types
--> $DIR/issue-84976.rs:17:14

View File

@ -23,6 +23,9 @@ LL | std::intrinsics::unlikely,
|
= note: expected fn item `extern "rust-intrinsic" fn(_) -> _ {likely}`
found fn item `extern "rust-intrinsic" fn(_) -> _ {unlikely}`
= note: different `fn` items always have unique types, even if their signatures are the same
= help: change the expected type to be function pointer `extern "rust-intrinsic" fn(bool) -> bool`
= 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`
error: aborting due to 3 previous errors

View File

@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/issue-74280.rs:9:5
|
LL | fn test() -> Test {
| ---- expected `_` because of return type
| ---- expected `()` because of return type
LL | let y = || -> Test { () };
LL | 7
| ^ expected `()`, found integer