Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Behavior of async fn and return position impl Future differs #109572

Closed
xiaoas opened this issue Mar 24, 2023 · 2 comments
Closed

Behavior of async fn and return position impl Future differs #109572

xiaoas opened this issue Mar 24, 2023 · 2 comments
Labels
C-bug Category: This is a bug.

Comments

@xiaoas
Copy link

xiaoas commented Mar 24, 2023

I tried this code:

use std::future::Future;

async fn call() {
    outer(inner).await;
}
async fn outer<F, Fut>(handler: F)
where
    F: Fn(&()) -> Fut,
    Fut: Future<Output = ()>,
{
    handler(&()).await;
}
async fn inner(_: &()) {
}

I expected to behave identically when I change the function inner to:

fn inner(_: &()) -> impl Future<Output = ()> {
    async {}
}

According to async-lifetimes, that is.

Instead, the -> impl Future version compiles fine, and the async function version give this error on current stable(1.68.1) & beta(1.69.0-beta.3):

error[E0308]: mismatched types
 --> src/lib.rs:4:5
  |
4 |     outer(inner).await;
  |     ^^^^^^^^^^^^ one type is more general than the other
  |
  = note: expected trait `for<'a> <for<'a> fn(&'a ()) -> impl Future<Output = ()> {inner} as FnOnce<(&'a (),)>>`
             found trait `for<'a> <for<'a> fn(&'a ()) -> impl Future<Output = ()> {inner} as FnOnce<(&'a (),)>>`
note: the lifetime requirement is introduced here
 --> src/lib.rs:8:19
  |
8 |     F: Fn(&()) -> Fut,
  |                   ^^^

For more information about this error, try `rustc --explain E0308`.

And this message on nightly:

error[E0308]: mismatched types
 --> src/lib.rs:4:5
  |
4 |     outer(inner).await;
  |     ^^^^^^^^^^^^ one type is more general than the other
  |
  = note: expected opaque type `impl for<'a> Future<Output = ()>`
             found opaque type `impl Future<Output = ()>`
  = help: consider `await`ing on both `Future`s
  = note: distinct uses of `impl Trait` result in different opaque types
note: the lifetime requirement is introduced here
 --> src/lib.rs:8:19
  |
8 |     F: Fn(&()) -> Fut,
  |                   ^^^

For more information about this error, try `rustc --explain E0308`.

Meta

rustc --version --verbose:
I tried stable, beta and nightly.

@xiaoas xiaoas added the C-bug Category: This is a bug. label Mar 24, 2023
@csmoe
Copy link
Member

csmoe commented Mar 25, 2023

Your async fn de-sugars to:

fn inner<'a>(_: &'a) -> impl 'a + Future<Output =()> { }

Note the extra 'a comparing to your fn -> impl Future, which is a early bound lifetime, rustc cannot make it into higher ranked reference, but F: Fn(&()) expects a hrtb.

If you capture the lifetime explicitly in the fn -> impl Future:

fn inner(_: &()) -> impl Future<Output = ()> + '_ {
    async {}
}

you'll get the same error again.

Duplicate of #41078

@xiaoas
Copy link
Author

xiaoas commented Mar 25, 2023

Does that means fn -> impl Future's returns a future that will live longer than 'a?

I would have expected the future become invalid once the reference goes out of scope.

Edit: I think there's an explanation in https://rust-lang.github.io/async-book/03_async_await/01_chapter.html#async-lifetimes .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug.
Projects
None yet
Development

No branches or pull requests

3 participants