I had problems expressing a Send
bound for a GAT within an async trait (using async-trait
). While composing an example, to show my problem, I noticed that the Playground acts differently than my local compiler. I thus updated my compiler to rustc 1.58.0-nightly (072799443 2021-11-06)
. This required me to add some extra bound in the code below (where Self: 'a
). But I then get another error that seems unfixable. See example below:
#![feature(generic_associated_types)]
use async_trait::async_trait;
use std::ops::Deref;
async fn some_async_task() {}
#[async_trait]
trait Source {
type T;
// I would like to remove the `Send` bound here:
type Wrapper<'a>: Deref<Target = Self::T> + Send
where
Self: 'a;
async fn retrieve(&mut self) -> Self::Wrapper<'_>;
}
struct S {
state: i32,
}
impl S {
fn new() -> Self {
S { state: 0 }
}
}
#[async_trait]
impl Source for S {
type T = i32;
type Wrapper<'a> = &'a Self::T;
async fn retrieve(&mut self) -> Self::Wrapper<'_> {
self.state += 1;
&self.state
}
}
#[async_trait]
trait User {
// But after updating nightly rustc, this won't work anymore:
async fn process<'a, 'b, S>(
&'a self,
source: &'b mut S,
) -> S::Wrapper<'b>
where
S: Source + Send,
{
let result = source.retrieve().await;
some_async_task().await;
result
}
}
struct U {}
#[async_trait]
impl User for U {}
#[tokio::main]
async fn main() {
let mut s = S::new();
let u = U {};
let value: &i32 = u.process(&mut s).await;
println!("Result = {}", value);
}
Errors:
Compiling playground v0.0.1 (/playground)
error[E0311]: the parameter type `S` may not live long enough
--> src/main.rs:47:5
|
41 | async fn process<'a, 'b, S>(
| - help: consider adding an explicit lifetime bound...: `S: 'c`
...
47 | / {
48 | | let result = source.retrieve().await;
49 | | some_async_task().await;
50 | | result
51 | | }
| |_____^ ...so that the type `S` will meet its required lifetime bounds
error: could not compile `playground` due to previous error
If I follow the compiler's advice literally, then of course I'll get:
error[E0261]: use of undeclared lifetime name `'c`
If I declare 'c
as a lifetime parameter, then the compiler demands I should add a bound S: 'd
, and so on. No idea what this is about and whether it's a problem of nightly Rust or of async-trait
.