Skip to content

warn: where_clauses_object_safety when adding default implementation for async_trait #228

Closed
rust-lang/rust
#107082
@NishantJoshi00

Description

@NishantJoshi00

Description

Getting warning #[warn(where_clauses_object_safety)] when adding default implementation for async_trait

Sample Case

use tokio::time;

#[async_trait::async_trait]
trait Waiter {
    async fn wait_inner_sec(&self, name: &str);
}

struct Walker {
    inner: u64,
}

impl Walker {
    fn new(inner: u64) -> Self { Self { inner } }
}

#[async_trait::async_trait]
impl Waiter for Walker {
    async fn wait_inner_sec(&self, name: &str) {
        println!("waiting for: {}", name);
        time::sleep(time::Duration::new(self.inner, 0)).await
    }
}

#[tokio::main]
async fn main() {
    let walker = Walker::new(1);
    let dyn_walker: Box<&(dyn Waiter)> = Box::new(&walker);
    dyn_walker.wait_inner_sec("plane").await;

}

This example works properly and there is no issue with object-safety here!

Now, if I add a default implementation for the trait

#[async_trait::async_trait]
trait Waiter {
  async fn wait_inner_sec(&self, name: &str) {
    println!("waiting for: {}", name);
    time::sleep(time::Duration::new(5, 0)).await
  }
}

After this change, I suddenly get 1 warning and 1 error.

The Error

error[E0277]: `dyn Waiter` cannot be shared between threads safely
  --> src/main.rs:31:5
   |
31 |     dyn_walker.wait_inner_sec("plane").await;
   |     ^^^^^^^^^^ -------------- required by a bound introduced by this call
   |     |
   |     `dyn Waiter` cannot be shared between threads safely
   |
   = help: the trait `Sync` is not implemented for `dyn Waiter`
note: required by a bound in `Waiter::wait_inner_sec`
  --> src/main.rs:5:5
   |
5  |     async fn wait_inner_sec(&self, name: &str) {
   |     ^^^^^ required by this bound in `Waiter::wait_inner_sec`

This can be solved with

- let dyn_walker: Box<&(dyn Waiter)> = Box::new(&walker);
+ let dyn_walker: Box<&(dyn Waiter + Sync)> = Box::new(&walker);

The Warning

warning: the trait `Waiter` cannot be made into an object
 --> src/main.rs:5:14
  |
5 |     async fn wait_inner_sec(&self, name: &str) {
  |              ^^^^^^^^^^^^^^
  |
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #51443 <https://github.com/rust-lang/rust/issues/51443>
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/main.rs:5:14
  |
4 | trait Waiter {
  |       ------ this trait cannot be made into an object...
5 |     async fn wait_inner_sec(&self, name: &str) {
  |              ^^^^^^^^^^^^^^ ...because method `wait_inner_sec` references the `Self` type in its `where` clause
  = help: consider moving `wait_inner_sec` to another trait
  = note: `#[warn(where_clauses_object_safety)]` on by default
  • The warning doesn't provide the whole context
  • In my implementation I haven't used any where clause.
  • After expanding the macro turns out the function has a where clause, where self is referenced Self: Sync
  • This problem can be solved by trait Waiter: Sync, but should this warning even occur?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions