Closed bbaldino closed 6 months ago
This is working correctly. This is how async fn
always works. When called, async fn
does nothing but construct a Future
to represent the state of the evaluation of the async code. Nothing in the body of the function begins to run until something begins polling the future.
You are suggesting to eagerly run Drop
impls for unused arguments before the future is polled, which would be incorrect behavior.
For example consider what would happen if some function argument holds a mutex guard. According to the semantics of async fn
that mutex is supposed to be held for the entire function body or until dropped during some poll call.
Hi @dtolnay , thanks for the response. Given that the following seems to compile fine:
trait Bar<K, V> {
async fn insert(&mut self, key: K, value: V);
}
struct Dummy;
impl<K, V> Bar<K, V> for Dummy {
async fn insert(&mut self, key: K, value: V) {
}
}
(i.e. using built-in async trait support instead of async_trait
), is there a way to achieve this behavior when using async_trait
?
The difference between that and the earlier playground link is not about when Drop impls get run, it is about what bounds the trait requires all implementations to guarantee on the async function's desugared return type. The native async fn in trait returns Self::InsertFuture<'life0, K, V>
which implements Future<Output = ()>
and includes all the lifetime bounds from K
and V
. The dynamically dispatched one returns Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
which does not mention K
and V
; you can add the lifetime bounds by writing them in the signature of insert
:
#[async_trait]
trait Bar<K, V> {
async fn insert(&mut self, key: K, value: V)
where
K: 'async_trait,
V: 'async_trait;
}
#[async_trait]
impl<K: Send, V: Send> Bar<K, V> for Dummy {
async fn insert(&mut self, key: K, value: V)
where
K: 'async_trait,
V: 'async_trait,
{
}
}
Got it. Thanks for the info.
I was recently playing with a dummy implementation of an async trait that, by design, doesn't do anything in its methods and ran into an issue with a lifetime complaint. You can see a playground example here.
For the
Dummy
impl case,async_trait
ends up generating:which then puts requirements on the lifetimes of
K
andV
which causes the error. It'd be nice if variables that are ignored (have a leading underscore) weren't declared in the async block. Or maybe some otherasync_trait
helper that would allow a user to suppress the generated block when it wasn't needed?