async-trait icon indicating copy to clipboard operation
async-trait copied to clipboard

Using `type` in async trait will cause some problems?

Open UkonnRa opened this issue 6 years ago • 2 comments

Hi, me again. I found using type in trait will cause some problems...

  1. mismatched types
  2. cannot infer an appropriate lifetime for lifetime parameter 'a due to conflicting requirements
extern crate async_trait;

use async_trait::async_trait;
use futures::executor::block_on;

#[async_trait]
pub trait State<'a> {
    type Command: 'a + Send;

    async fn add_comm(mut self, more_str: Self::Command) -> Self where Self: Sized;
    async fn add_more_comm(mut self, str1: Self::Command, str2: Self::Command) -> Self where Self: Sized {
        let self1 = self.add_comm(str1).await;
        let self2 = self1.add_comm(str2).await;
        self2
    }
}

#[derive(Debug)]
pub struct RealState(String);
#[async_trait]
impl <'a> State<'a> for RealState {
    type Command = String;

    async fn add_comm(mut self, more_str: Self::Command) -> Self {
        self.0 = self.0.clone() + more_str.as_ref();
        self
    }
}

fn main() {
    let state = RealState(Default::default());
    let state1 = block_on(state.add_more_str("hello", " world"));
    println!("{:?}", state1);
}

Error:

error[E0308]: mismatched types
 --> src/lifetime-error.rs:6:1
  |
6 | #[async_trait]
  | ^^^^^^^^^^^^^^ one type is more general than the other
  |
  = note: expected type `std::marker::Send`
             found type `std::marker::Send`

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
 --> src/lifetime-error.rs:6:1
  |
6 | #[async_trait]
  | ^^^^^^^^^^^^^^
  |
note: first, the lifetime cannot outlive the lifetime 'a as defined on the trait at 7:17...
 --> src/lifetime-error.rs:7:17
  |
7 | pub trait State<'a> {
  |                 ^^
  = note: ...so that the expression is assignable:
          expected <Self as State<'_>>::Command
             found <Self as State<'a>>::Command
note: but, the lifetime must be valid for the lifetime 'async_trait as defined on the method body at 6:1...
 --> src/lifetime-error.rs:6:1
  |
6 | #[async_trait]
  | ^^^^^^^^^^^^^^
  = note: ...so that the expression is assignable:
          expected std::pin::Pin<std::boxed::Box<(dyn core::future::future::Future<Output = Self> + std::marker::Send + 'async_trait)>>
             found std::pin::Pin<std::boxed::Box<dyn core::future::future::Future<Output = Self> + std::marker::Send>>

UkonnRa avatar Sep 16 '19 08:09 UkonnRa

This is a compiler bug. :cry: https://github.com/rust-lang/rust/issues/60658

dtolnay avatar Sep 18 '19 09:09 dtolnay

I've run in to one type is more general than the other with the same types as well.

   | |_____^ one type is more general than the other
   |
   = note: expected type `FnOnce<(&Model,)>`
              found type `FnOnce<(&Model,)>`

This error only happens when the function call is in, or downstream of, an async_trait fn impl. There is no error when calling from outside an async_trait context.

I'm trying to figure out if this is the same issue or a different one? I've widdled down this repro (playground). The buffer_unordered() stream wrapper seems to trigger the issue. Calling the working function in build compiles.

wpbrown avatar Feb 20 '21 20:02 wpbrown

Closing in favor of https://github.com/rust-lang/rust/issues/60658, since this is not going to be actionable in async-trait. We can reopen in the event that the rustc bug gets fixed in a way that doesn't immediately solve this.

dtolnay avatar Nov 26 '22 20:11 dtolnay