#![feature(async_await, futures_api)]
use std::future::Future;
trait Foo<'a> {
type Future: Future<Output = u8> + 'a;
fn start(self, f: &'a u8) -> Self::Future;
}
impl<'a, Fn, Fut> Foo<'a> for Fn
where
Fn: FnOnce(&'a u8) -> Fut,
Fut: Future<Output = u8> + 'a,
{
type Future = Fut;
fn start(self, f: &'a u8) -> Self::Future { (self)(f) }
}
fn foo<F>(f: F) where F: for<'a> Foo<'a> {
let bar = 5;
f.start(&bar);
}
fn main() {
foo(async move | f: &u8 | { *f });
foo({ async fn baz(f: &u8) -> u8 { *f } baz });
}
(playground) currently errors with
error: implementation of `Foo` is not general enough
--> src/main.rs:27:5
|
27 | foo(async move | f: &u8 | { *f });
| ^^^
|
= note: Due to a where-clause on `foo`,
= note: `Foo<'1>` would have to be implemented for the type `[closure@src/main.rs:27:9: 27:37]`, for any lifetime `'1`
= note: but `Foo<'_>` is actually implemented for the type `[closure@src/main.rs:27:9: 27:37]`, for some specific lifetime `'2`
You can see that the async fn correctly satisfies the HRLB required by foo, but the async closure has a concrete lifetime for the argument instead of being for any lifetime.
@rustbot modify labels: A-async-await and T-compiler.
Interestingly, using trait aliases instead of the extra trait above gives a different error message, not sure exactly what it believes is wrong here (could easily be a trait alias issue rather than an async closure issue) (playground)
#![feature(async_await, futures_api, trait_alias, unboxed_closures)]
use std::future::Future;
trait Foo<'a> = FnOnce<(&'a u8,)> where <Self as FnOnce<(&'a u8,)>>::Output: Future<Output = u8> + 'a;
fn foo<F>(f: F) where F: for<'a> Foo<'a> {
let bar = 5;
f(&bar);
}
fn main() {
foo(async move | f: &u8 | { *f });
foo({ async fn baz(f: &u8) -> u8 { *f } baz });
}
error[E0477]: the type `impl std::future::Future` does not fulfill the required lifetime
--> src/main.rs:13:5
|
13 | foo(async move | f: &u8 | { *f });
| ^^^
|
= note: type must outlive any other region
Marking as deferred since async closures are not considered part of the "core functionality" we are trying to stabilize.
I think this is actually a problem with regular closures. It's just a lot more noticeable with async closures. In the working example, replace:
foo({ async fn baz(f: &u8) -> u8 { *f } baz });
with:
foo({ async fn baz(f: &u8) -> u8 { *f } |f| baz(f) });
This isn't an async closure. It should have the same function signature as baz, taking a borrowed u8 and returning a future. However, it doesn't compile:
error[E0308]: mismatched types
--> src/main.rs:15:5
|
15 | foo({ async fn baz(f: &u8) -> u8 { *f } |f| baz(f) });
| ^^^ one type is more general than the other
|
= note: expected type `std::ops::FnOnce<(&'a u8,)>`
found type `std::ops::FnOnce<(&u8,)>`
I just ran into this too: in relation to async/await, but in a situation that does not require a nightly compiler:
I think the "requires-nightly" label should be removed as this is clearly a broader problem that affects all closures.
It seems like it might be a problem with the type inference of the closures return type? It ends up inferring the return type to be impl Future instead of impl Future + 'a.
Most helpful comment
I think this is actually a problem with regular closures. It's just a lot more noticeable with async closures. In the working example, replace:
with:
This isn't an async closure. It should have the same function signature as baz, taking a borrowed u8 and returning a future. However, it doesn't compile: