dtolnay / async-trait

Type erasure for async trait methods
Apache License 2.0
1.81k stars 84 forks source link

async_trait with impl parameter #188

Closed lquerel closed 2 years ago

lquerel commented 2 years ago

I don't understand why this code doesn't compile.

#[async_trait]
pub trait Receiver<Msg: 'static + Clone + Send>: Send {
    fn is_singleton(&self) -> bool;

    async fn init(&mut self, configurator: Configurator) -> Result<(), Error>;
    async fn run(&mut self, mut effect_handler: impl EffectHandler<Msg>) -> Result<(), Error>;
    async fn stop(&mut self) {}
}

The error returned by the compiler is:

error[E0038]: the trait `Receiver` cannot be made into an object
  --> crates/receiver/src/lib.rs:56:82
   |
56 |     fn create(&self, receiver_name: &str, receiver_type: &str, config: Value) -> Result<Box<dyn Receiver<Msg> + Send + Sync>, Error>;
   |                                                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Receiver` cannot be made into an object
   |
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
  --> crates/receiver/src/lib.rs:51:14
   |
47 | pub trait Receiver<Msg: 'static + Clone + Send>: Send {
   |           -------- this trait cannot be made into an object...
...
51 |     async fn run(&mut self, mut effect_handler: impl EffectHandler<Msg>) -> Result<(), Error>;
   |              ^^^ ...because method `run` has generic type parameters
   = help: consider moving `run` to another trait

Note that I'd like to keep impl the effect_handler parameter in the run method.

Thanks

dtolnay commented 2 years ago

I don't believe this has anything to do with async_trait.

struct Error;
struct Configurator;
struct Msg;
trait EffectHandler<Msg> {}

trait Receiver<Msg: 'static + Clone + Send>: Send {
    fn is_singleton(&self) -> bool;
    fn init(&mut self, configurator: Configurator) -> Result<(), Error>;
    fn run(&mut self, effect_handler: impl EffectHandler<Msg>) -> Result<(), Error>;
    fn stop(&mut self) {}
}

fn create() -> Result<Box<dyn Receiver<Msg> + Send + Sync>, Error> {unimplemented!()}
error[E0038]: the trait `Receiver` cannot be made into an object
  --> src/lib.rs:13:16
   |
13 | fn create() -> Result<Box<dyn Receiver<Msg> + Send + Sync>, Error> {unimplemented!()}
   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Receiver` cannot be made into an object
   |
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
  --> src/lib.rs:9:8
   |
6  | trait Receiver<Msg: 'static + Clone + Send>: Send {
   |       -------- this trait cannot be made into an object...
...
9  |     fn run(&mut self, effect_handler: impl EffectHandler<Msg>) -> Result<(), Error>;
   |        ^^^ ...because method `run` has generic type parameters
   = help: consider moving `run` to another trait
lquerel commented 2 years ago

Indeed. My bad :)