Rollup merge of #135492 - metamuffin:bug-invalid-await-suggest, r=compiler-errors

Add missing check for async body when suggesting await on futures.

Currently the compiler suggests adding `.await` to resolve some type conflicts without checking if the conflict happens in an async context. This can lead to the compiler suggesting `.await` in function signatures where it is invalid. Example:

```rs
trait A {
    fn a() -> impl Future<Output = ()>;
}
struct B;
impl A for B {
    fn a() -> impl Future<Output = impl Future<Output = ()>> {
        async { async { () } }
    }
}
```
```
error[E0271]: expected `impl Future<Output = impl Future<Output = ()>>` to be a future that resolves to `()`, but it resolves to `impl Future<Output = ()>`
 --> bug.rs:6:15
  |
6 |     fn a() -> impl Future<Output = impl Future<Output = ()>> {
  |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found future
  |
note: calling an async function returns a future
 --> bug.rs:6:15
  |
6 |     fn a() -> impl Future<Output = impl Future<Output = ()>> {
  |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `A::{synthetic#0}`
 --> bug.rs:2:27
  |
2 |     fn a() -> impl Future<Output = ()>;
  |                           ^^^^^^^^^^^ required by this bound in `A::{synthetic#0}`
help: consider `await`ing on the `Future`
  |
6 |     fn a() -> impl Future<Output = impl Future<Output = ()>>.await {
  |                                                             ++++++
```

The documentation of suggest_await_on_expect_found (`compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs:156`) even mentions such a check but does not actually implement it.

This PR adds that check to ensure `.await` is only suggested within async blocks.

There were 3 unit tests whose expected output needed to be changed because they had the suggestion outside of async. One of them (`tests/ui/async-await/dont-suggest-missing-await.rs`) actually tests that exact problem but expects it to be present.

Thanks to `@llenck` for initially noticing the bug and helping with fixing it
This commit is contained in:
Matthias Krüger 2025-01-23 19:54:24 +01:00 committed by GitHub
commit 4496f23ca9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 12 additions and 19 deletions

View file

@ -167,6 +167,18 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
exp_span, exp_found.expected, exp_found.found,
);
match self.tcx.coroutine_kind(cause.body_id) {
Some(hir::CoroutineKind::Desugared(
hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::AsyncGen,
_,
)) => (),
None
| Some(
hir::CoroutineKind::Coroutine(_)
| hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _),
) => return,
}
if let ObligationCauseCode::CompareImplItem { .. } = cause.code() {
return;
}