dtolnay / async-trait

Type erasure for async trait methods
Apache License 2.0
1.84k stars 85 forks source link

error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds #48

Closed nirui closed 5 years ago

nirui commented 5 years ago

Hello,

I was trying to spawn an async block inside another async function with Tokio (which requires the async block to be Future<Output = ()> + Send + 'static, so I had to borrow other_trait as 'static as well). Rust tells me somehow my code is an E0700.

The minified version of my code as following:

trait AnotherTrait: Send + Sync {
    fn test(&self);
}

trait Test2 {
    // This one without async fn
    fn test2<'a>(&self, other_trait: &'static impl AnotherTrait) -> Result<&'a str, ()>;
}

use async_trait::async_trait;
#[async_trait]
trait Test {
    // This one with async fn
    async fn test<'a>(&self, other_trait: &'static impl AnotherTrait) -> Result<&'a str, ()>;
}

use tokio::runtime;

struct ImplTest {}

impl Test2 for ImplTest {
    fn test2<'a>(&self, other_trait: &'static impl AnotherTrait) -> Result<&'a str, ()> {
        println!("Hello, world!");

        match runtime::Runtime::new() {
            Err(e) => panic!(e),
            Ok(t) => t.spawn(async move {
                other_trait.test();
            }),
        };

        Ok("Ok")
    }
}

#[async_trait]
impl Test for ImplTest {
    async fn test<'a>(&self, other_trait: &'static impl AnotherTrait) -> Result<&'a str, ()> {
        println!("Hello, world!");

        match runtime::Runtime::new() {
            Err(e) => panic!(e),
            Ok(t) => t.spawn(async move {
                other_trait.test();
            }),
        };

        Ok("Ok")
    }
}

fn main() {
    ImplTest {};
}

Cargo.toml file:

[package]
name = "async_trait_E0700"
version = "0.1.0"
authors = ["Noop"]
edition = "2018"

[dependencies]
async-trait = "0.1.17"
futures-preview = {version = "0.3.0-alpha.18", features = ["async-await"]}
tokio = "0.2.0-alpha.5"

Error message:

error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
  --> src/main.rs:38:74
   |
38 |     async fn test<'a>(&self, other_trait: &'static impl AnotherTrait) -> Result<&'a str, ()> {
   |                                                                          ^^^^^^^^^^^^^^^^^^^
   |
note: hidden type `impl std::future::Future` captures the scope of call-site for function at 38:94
  --> src/main.rs:38:94
   |
38 |       async fn test<'a>(&self, other_trait: &'static impl AnotherTrait) -> Result<&'a str, ()> {
   |  ______________________________________________________________________________________________^
39 | |         println!("Hello, world!");
40 | |
41 | |         match runtime::Runtime::new() {
...  |
48 | |         Ok("Ok")
49 | |     }
   | |_____^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0700`.
error: could not compile `async_trait_E0700`.

I'm still learning all the pieces of the puzzle of Rust, so I'm not sure about whether it's my mistake or a bug. Sorry for bothering if it's me been dumb :(

PS: I've read the #15, but not sure my problem is related.

Thank you!

dtolnay commented 5 years ago

This looks like it affects any function with a signature resembling async fn<'a>(&A, &'static B) -> &'a C, not anything about async-trait. Could you make sure there is an issue filed for this in rust-lang/rust?

Minimized further:

async fn test<'a>(_: &(), _: &'static ()) -> &'a () {
    unimplemented!()
}
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
 --> src/main.rs:1:46
  |
1 | async fn test<'a>(_: &(), _: &'static ()) -> &'a () {
  |                                              ^^^^^^
  |
note: hidden type `impl std::future::Future` captures the scope of call-site for function at 1:53
 --> src/main.rs:1:53
  |
1 |   async fn test<'a>(_: &(), _: &'static ()) -> &'a () {
  |  _____________________________________________________^
2 | |     unimplemented!()
3 | | }
  | |_^
nirui commented 5 years ago

async fn test<'a>(_: &(), _: &'static ()) -> &'a () { unimplemented!() }

Nice catch! I'll investigate some more into the language itself.

Thank you for your time! And sorry for the bothering.

fzzzy commented 4 years ago

I just hit this same rust compiler bug in some code that doesn't use async trait. Did this ever get filed as a bug against rustc?

jrconlin commented 4 years ago

Looks like https://github.com/rust-lang/rust/issues/64552 might be related?