Skip to content

Commit

Permalink
Rollup merge of #107902 - vincenzopalazzo:macros/async_fn_suggestion,…
Browse files Browse the repository at this point in the history
… r=compiler-errors

fix: improve the suggestion on future not awaited

Considering the following code

```rust
fn foo() -> u8 {
    async fn async_fn() -> u8 {  22 }

    async_fn()
}

fn main() {}
```

the error generated before this commit from the compiler is

```
➜  rust git:(macros/async_fn_suggestion) ✗ rustc test.rs --edition 2021
error[E0308]: mismatched types
 --> test.rs:4:5
  |
1 | fn foo() -> u8 {
  |             -- expected `u8` because of return type
...
4 |     async_fn()
  |     ^^^^^^^^^^ expected `u8`, found opaque type
  |
  = note:     expected type `u8`
          found opaque type `impl Future<Output = u8>`
help: consider `await`ing on the `Future`
  |
4 |     async_fn().await
  |               ++++++

error: aborting due to previous error
```

In this case the error is nor perfect, and can confuse the user that do not know that the opaque type is the future.

So this commit will propose (and conclude the work start in #80658)
to change the string `opaque type` to `future` when applicable and also remove the Expected vs Received note by adding a more specific one regarding the async function that return a future type.

So the new error emitted by the compiler is

```
error[E0308]: mismatched types
 --> test.rs:4:5
  |
1 | fn foo() -> u8 {
  |             -- expected `u8` because of return type
...
4 |     async_fn()
  |     ^^^^^^^^^^ expected `u8`, found future
  |
note: calling an async function returns a future
 --> test.rs:4:5
  |
4 |     async_fn()
  |     ^^^^^^^^^^
help: consider `await`ing on the `Future`
  |
4 |     async_fn().await
  |               ++++++

error: aborting due to previous error
```

Fixes #80658

It remains to rework the case described in the following issue #107899 but I think this deserves its own PR after we discuss a little bit how to handle these kinds of cases.

r? `@eholk`

`@rustbot` label +I-async-nominated

Signed-off-by: Vincenzo Palazzo <vincenzopalazzodev@gmail.com>
  • Loading branch information
matthiaskrgr authored Feb 13, 2023
2 parents a3c9eed + 2bdc9a0 commit 73b022b
Show file tree
Hide file tree
Showing 22 changed files with 132 additions and 116 deletions.
34 changes: 25 additions & 9 deletions compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1783,14 +1783,24 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
}))
{
diag.note_expected_found_extra(
&expected_label,
expected,
&found_label,
found,
&sort_string(values.expected, exp_p),
&sort_string(values.found, found_p),
);
if let Some(ExpectedFound { found: found_ty, .. }) = exp_found {
// `Future` is a special opaque type that the compiler
// will try to hide in some case such as `async fn`, so
// to make an error more use friendly we will
// avoid to suggest a mismatch type with a
// type that the user usually are not usign
// directly such as `impl Future<Output = u8>`.
if !self.tcx.ty_is_opaque_future(found_ty) {
diag.note_expected_found_extra(
&expected_label,
expected,
&found_label,
found,
&sort_string(values.expected, exp_p),
&sort_string(values.found, found_p),
);
}
}
}
}
_ => {
Expand Down Expand Up @@ -2854,6 +2864,7 @@ impl IntoDiagnosticArg for ObligationCauseAsDiagArg<'_> {
pub enum TyCategory {
Closure,
Opaque,
OpaqueFuture,
Generator(hir::GeneratorKind),
Foreign,
}
Expand All @@ -2863,6 +2874,7 @@ impl TyCategory {
match self {
Self::Closure => "closure",
Self::Opaque => "opaque type",
Self::OpaqueFuture => "future",
Self::Generator(gk) => gk.descr(),
Self::Foreign => "foreign type",
}
Expand All @@ -2871,7 +2883,11 @@ impl TyCategory {
pub fn from_ty(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Self, DefId)> {
match *ty.kind() {
ty::Closure(def_id, _) => Some((Self::Closure, def_id)),
ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => Some((Self::Opaque, def_id)),
ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
let kind =
if tcx.ty_is_opaque_future(ty) { Self::OpaqueFuture } else { Self::Opaque };
Some((kind, def_id))
}
ty::Generator(def_id, ..) => {
Some((Self::Generator(tcx.generator_kind(def_id).unwrap()), def_id))
}
Expand Down
31 changes: 13 additions & 18 deletions compiler/rustc_infer/src/infer/error_reporting/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,31 +238,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
},
(_, Some(ty)) if self.same_type_modulo_infer(exp_found.expected, ty) => {
diag.span_suggestion_verbose(
exp_span.shrink_to_hi(),
"consider `await`ing on the `Future`",
".await",
Applicability::MaybeIncorrect,
);
self.suggest_await_on_future(diag, exp_span);
diag.span_note(exp_span, "calling an async function returns a future");
}
(Some(ty), _) if self.same_type_modulo_infer(ty, exp_found.found) => match cause.code()
{
ObligationCauseCode::Pattern { span: Some(then_span), .. } => {
diag.span_suggestion_verbose(
then_span.shrink_to_hi(),
"consider `await`ing on the `Future`",
".await",
Applicability::MaybeIncorrect,
);
self.suggest_await_on_future(diag, then_span.shrink_to_hi());
}
ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => {
let then_span = self.find_block_span_from_hir_id(*then_id);
diag.span_suggestion_verbose(
then_span.shrink_to_hi(),
"consider `await`ing on the `Future`",
".await",
Applicability::MaybeIncorrect,
);
self.suggest_await_on_future(diag, then_span.shrink_to_hi());
}
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
ref prior_arms,
Expand All @@ -283,6 +269,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
}

pub fn suggest_await_on_future(&self, diag: &mut Diagnostic, sp: Span) {
diag.span_suggestion_verbose(
sp.shrink_to_hi(),
"consider `await`ing on the `Future`",
".await",
Applicability::MaybeIncorrect,
);
}

pub(super) fn suggest_accessing_field_where_appropriate(
&self,
cause: &ObligationCause<'tcx>,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ impl<'tcx> Ty<'tcx> {
ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(),
ty::Alias(ty::Projection, _) => "associated type".into(),
ty::Param(p) => format!("type parameter `{p}`").into(),
ty::Alias(ty::Opaque, ..) => "opaque type".into(),
ty::Alias(ty::Opaque, ..) => if tcx.ty_is_opaque_future(self) { "future".into() } else { "opaque type".into() },
ty::Error(_) => "type error".into(),
_ => {
let width = tcx.sess.diagnostic_width();
Expand Down
9 changes: 6 additions & 3 deletions tests/ui/async-await/dont-suggest-missing-await.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ error[E0308]: mismatched types
--> $DIR/dont-suggest-missing-await.rs:14:18
|
LL | take_u32(x)
| -------- ^ expected `u32`, found opaque type
| -------- ^ expected `u32`, found future
| |
| arguments to this function are incorrect
|
= note: expected type `u32`
found opaque type `impl Future<Output = u32>`
note: calling an async function returns a future
--> $DIR/dont-suggest-missing-await.rs:14:18
|
LL | take_u32(x)
| ^
note: function defined here
--> $DIR/dont-suggest-missing-await.rs:5:4
|
Expand Down
4 changes: 1 addition & 3 deletions tests/ui/async-await/generator-desc.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,10 @@ error[E0308]: mismatched types
--> $DIR/generator-desc.rs:12:16
|
LL | fun(one(), two());
| --- ^^^^^ expected opaque type, found a different opaque type
| --- ^^^^^ expected future, found a different future
| |
| arguments to this function are incorrect
|
= note: expected opaque type `impl Future<Output = ()>` (opaque type at <$DIR/generator-desc.rs:5:16>)
found opaque type `impl Future<Output = ()>` (opaque type at <$DIR/generator-desc.rs:6:16>)
= help: consider `await`ing on both `Future`s
= note: distinct uses of `impl Trait` result in different opaque types
note: function defined here
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0053]: method `foo` has an incompatible type for trait
--> $DIR/async-example-desugared-boxed-in-trait.rs:15:28
|
LL | async fn foo(&self) -> i32 {
| ^^^ expected `Pin<Box<dyn Future<Output = i32>>>`, found opaque type
| ^^^ expected `Pin<Box<dyn Future<Output = i32>>>`, found future
|
note: type in trait
--> $DIR/async-example-desugared-boxed-in-trait.rs:11:22
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/async-await/issue-61076.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ async fn match_() {
match tuple() { //~ HELP consider `await`ing on the `Future`
//~^ NOTE this expression has type `impl Future<Output = Tuple>`
Tuple(_) => {} //~ ERROR mismatched types
//~^ NOTE expected opaque type, found `Tuple`
//~^ NOTE expected future, found `Tuple`
//~| NOTE expected opaque type `impl Future<Output = Tuple>`
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/async-await/issue-61076.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ LL | match tuple() {
| ------- this expression has type `impl Future<Output = Tuple>`
LL |
LL | Tuple(_) => {}
| ^^^^^^^^ expected opaque type, found `Tuple`
| ^^^^^^^^ expected future, found `Tuple`
|
= note: expected opaque type `impl Future<Output = Tuple>`
found struct `Tuple`
Expand Down
12 changes: 3 additions & 9 deletions tests/ui/async-await/issue-98634.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ error[E0271]: expected `callback` to be a fn item that returns `Pin<Box<dyn Futu
--> $DIR/issue-98634.rs:45:23
|
LL | StructAsync { callback }.await;
| ^^^^^^^^ expected `Pin<Box<dyn Future<Output = ()>>>`, found opaque type
| ^^^^^^^^ expected `Pin<Box<dyn Future<Output = ()>>>`, found future
|
= note: expected struct `Pin<Box<(dyn Future<Output = ()> + 'static)>>`
found opaque type `impl Future<Output = ()>`
note: required by a bound in `StructAsync`
--> $DIR/issue-98634.rs:9:35
|
Expand All @@ -16,10 +14,8 @@ error[E0271]: expected `callback` to be a fn item that returns `Pin<Box<dyn Futu
--> $DIR/issue-98634.rs:45:9
|
LL | StructAsync { callback }.await;
| ^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<Box<dyn Future<Output = ()>>>`, found opaque type
| ^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<Box<dyn Future<Output = ()>>>`, found future
|
= note: expected struct `Pin<Box<(dyn Future<Output = ()> + 'static)>>`
found opaque type `impl Future<Output = ()>`
note: required by a bound in `StructAsync`
--> $DIR/issue-98634.rs:9:35
|
Expand All @@ -30,10 +26,8 @@ error[E0271]: expected `callback` to be a fn item that returns `Pin<Box<dyn Futu
--> $DIR/issue-98634.rs:45:33
|
LL | StructAsync { callback }.await;
| ^^^^^^ expected `Pin<Box<dyn Future<Output = ()>>>`, found opaque type
| ^^^^^^ expected `Pin<Box<dyn Future<Output = ()>>>`, found future
|
= note: expected struct `Pin<Box<(dyn Future<Output = ()> + 'static)>>`
found opaque type `impl Future<Output = ()>`
note: required by a bound in `StructAsync`
--> $DIR/issue-98634.rs:9:35
|
Expand Down
4 changes: 1 addition & 3 deletions tests/ui/async-await/issues/issue-102206.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ error[E0308]: mismatched types
LL | std::mem::size_of_val(foo());
| --------------------- ^^^^^
| | |
| | expected `&_`, found opaque type
| | expected `&_`, found future
| | help: consider borrowing here: `&foo()`
| arguments to this function are incorrect
|
= note: expected reference `&_`
found opaque type `impl Future<Output = ()>`
note: function defined here
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL

Expand Down
9 changes: 6 additions & 3 deletions tests/ui/async-await/suggest-missing-await-closure.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ error[E0308]: mismatched types
--> $DIR/suggest-missing-await-closure.rs:16:18
|
LL | take_u32(x)
| -------- ^ expected `u32`, found opaque type
| -------- ^ expected `u32`, found future
| |
| arguments to this function are incorrect
|
= note: expected type `u32`
found opaque type `impl Future<Output = u32>`
note: calling an async function returns a future
--> $DIR/suggest-missing-await-closure.rs:16:18
|
LL | take_u32(x)
| ^
note: function defined here
--> $DIR/suggest-missing-await-closure.rs:6:4
|
Expand Down
28 changes: 17 additions & 11 deletions tests/ui/async-await/suggest-missing-await.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ error[E0308]: mismatched types
--> $DIR/suggest-missing-await.rs:12:14
|
LL | take_u32(x)
| -------- ^ expected `u32`, found opaque type
| -------- ^ expected `u32`, found future
| |
| arguments to this function are incorrect
|
= note: expected type `u32`
found opaque type `impl Future<Output = u32>`
note: calling an async function returns a future
--> $DIR/suggest-missing-await.rs:12:14
|
LL | take_u32(x)
| ^
note: function defined here
--> $DIR/suggest-missing-await.rs:3:4
|
Expand All @@ -22,10 +25,13 @@ error[E0308]: mismatched types
--> $DIR/suggest-missing-await.rs:22:5
|
LL | dummy()
| ^^^^^^^ expected `()`, found opaque type
| ^^^^^^^ expected `()`, found future
|
= note: expected unit type `()`
found opaque type `impl Future<Output = ()>`
note: calling an async function returns a future
--> $DIR/suggest-missing-await.rs:22:5
|
LL | dummy()
| ^^^^^^^
help: consider `await`ing on the `Future`
|
LL | dummy().await
Expand All @@ -45,7 +51,7 @@ LL | | dummy()
LL | |
LL | | } else {
LL | | dummy().await
| | ^^^^^^^^^^^^^ expected opaque type, found `()`
| | ^^^^^^^^^^^^^ expected future, found `()`
LL | |
LL | | };
| |_____- `if` and `else` have incompatible types
Expand All @@ -67,7 +73,7 @@ LL | | 0 => dummy(),
LL | | 1 => dummy(),
| | ------- this is found to be of type `impl Future<Output = ()>`
LL | | 2 => dummy().await,
| | ^^^^^^^^^^^^^ expected opaque type, found `()`
| | ^^^^^^^^^^^^^ expected future, found `()`
LL | |
LL | | };
| |_____- `match` arms have incompatible types
Expand All @@ -86,7 +92,7 @@ error[E0308]: mismatched types
LL | let _x = match dummy() {
| ------- this expression has type `impl Future<Output = ()>`
LL | () => {}
| ^^ expected opaque type, found `()`
| ^^ expected future, found `()`
|
= note: expected opaque type `impl Future<Output = ()>`
found unit type `()`
Expand All @@ -102,7 +108,7 @@ LL | match dummy_result() {
| -------------- this expression has type `impl Future<Output = Result<(), ()>>`
...
LL | Ok(_) => {}
| ^^^^^ expected opaque type, found `Result<_, _>`
| ^^^^^ expected future, found `Result<_, _>`
|
= note: expected opaque type `impl Future<Output = Result<(), ()>>`
found enum `Result<_, _>`
Expand All @@ -118,7 +124,7 @@ LL | match dummy_result() {
| -------------- this expression has type `impl Future<Output = Result<(), ()>>`
...
LL | Err(_) => {}
| ^^^^^^ expected opaque type, found `Result<_, _>`
| ^^^^^^ expected future, found `Result<_, _>`
|
= note: expected opaque type `impl Future<Output = Result<(), ()>>`
found enum `Result<_, _>`
Expand Down
9 changes: 6 additions & 3 deletions tests/ui/impl-trait/issue-102605.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ error[E0308]: mismatched types
--> $DIR/issue-102605.rs:13:20
|
LL | convert_result(foo())
| -------------- ^^^^^ expected `Result<(), _>`, found opaque type
| -------------- ^^^^^ expected `Result<(), _>`, found future
| |
| arguments to this function are incorrect
|
= note: expected enum `Result<(), _>`
found opaque type `impl Future<Output = Result<(), String>>`
note: calling an async function returns a future
--> $DIR/issue-102605.rs:13:20
|
LL | convert_result(foo())
| ^^^^^
note: function defined here
--> $DIR/issue-102605.rs:7:4
|
Expand Down
4 changes: 1 addition & 3 deletions tests/ui/impl-trait/issue-99914.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ error[E0308]: mismatched types
--> $DIR/issue-99914.rs:9:27
|
LL | t.and_then(|t| -> _ { bar(t) });
| ^^^^^^ expected `Result<_, Error>`, found opaque type
| ^^^^^^ expected `Result<_, Error>`, found future
|
= note: expected enum `Result<_, Error>`
found opaque type `impl Future<Output = ()>`
help: try wrapping the expression in `Ok`
|
LL | t.and_then(|t| -> _ { Ok(bar(t)) });
Expand Down
11 changes: 5 additions & 6 deletions tests/ui/suggestions/if-then-neeing-semi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ async fn async_extra_semicolon_same() {
//~^ HELP consider removing this semicolon
} else {
async_dummy() //~ ERROR `if` and `else` have incompatible types
//~^ NOTE expected `()`, found opaque type
//~| NOTE expected unit type `()`
//~^ NOTE expected `()`, found future
//~| NOTE calling an async function returns a future
//~| HELP consider `await`ing on the `Future`
};
}
Expand All @@ -39,8 +39,8 @@ async fn async_extra_semicolon_different() {
//~^ HELP consider removing this semicolon
} else {
async_dummy2() //~ ERROR `if` and `else` have incompatible types
//~^ NOTE expected `()`, found opaque type
//~| NOTE expected unit type `()`
//~^ NOTE expected `()`, found future
//~| NOTE calling an async function returns a future
//~| HELP consider `await`ing on the `Future`
};
}
Expand All @@ -52,8 +52,7 @@ async fn async_different_futures() {
//~| HELP consider `await`ing on both `Future`s
} else {
async_dummy2() //~ ERROR `if` and `else` have incompatible types
//~^ NOTE expected opaque type, found a different opaque type
//~| NOTE expected opaque type `impl Future<Output = ()>`
//~^ NOTE expected future, found a different future
//~| NOTE distinct uses of `impl Trait` result in different opaque types
};
}
Expand Down
Loading

0 comments on commit 73b022b

Please sign in to comment.