rust icon indicating copy to clipboard operation
rust copied to clipboard

`dyn XXX` had impl `Debug`, but `dyn XXX + Send` can't Debug.

Open rise0chen opened this issue 3 years ago • 7 comments

I tried this code:

#[async_trait]
pub trait ConnectionDriver {
    ...
}
impl fmt::Debug for dyn ConnectionDriver {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        ...
    }
}

type C = Box<dyn ConnectionDriver + Send>;
pub struct Connection(C);
impl Connection {
    pub fn new(c: C) -> Connection {
        Connection(c)
    }
}
impl Deref for Connection {
    type Target = C;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
impl DerefMut for Connection {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

fn main() {
    let conn = Connection::new(Box::new());
    println!("{:?}", conn);
}

image

Meta

rustc --version --verbose:

rustc 1.62.0-nightly (de1026a67 2022-04-23)
binary: rustc
commit-hash: de1026a67b0a3f5d6b61a1f77093af97d4799376
commit-date: 2022-04-23
host: x86_64-pc-windows-msvc
release: 1.62.0-nightly
LLVM version: 14.0.1
Backtrace

   Compiling unmp-net v0.8.0 (D:\Desktop\crise\project\unmp\unmp.example.rust\unmp-net)
error[E0277]: `dyn unmp_link::connection::ConnectionDriver + core::marker::Send` doesn't implement `core::fmt::Debug`                      
  --> unmp-net\src\conns.rs:60:57
   |
60 |                         log::warn!("{:?} disconnected", conn.as_ref());
   |                                                         ^^^^^^^^^^^^^ `dyn unmp_link::connection::ConnectionDriver + core::marker::Send` cannot be formatted using `{:?}` because it doesn't implement `core::fmt::Debug`
   |
   = help: the trait `core::fmt::Debug` is not implemented for `dyn unmp_link::connection::ConnectionDriver + core::marker::Send`
   = help: the following other types implement trait `core::fmt::Debug`:
             (dyn Any + 'static)
             (dyn Any + Sync + core::marker::Send + 'static)
             (dyn Any + core::marker::Send + 'static)
             (dyn unmp_link::connection::ConnectionDriver + 'static)
             (dyn unmp_link::listener::ListenerDriver + 'static)
   = note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: `dyn unmp_link::connection::ConnectionDriver + core::marker::Send` doesn't implement `core::fmt::Debug`
  --> unmp-net\src\conns.rs:28:38
   |
28 |         log::info!("{:?} connected", conn.as_ref());
   |                                      ^^^^^^^^^^^^^ `dyn unmp_link::connection::ConnectionDriver + core::marker::Send` cannot be formatted using `{:?}` because it doesn't implement `core::fmt::Debug`
   |
   = help: the trait `core::fmt::Debug` is not implemented for `dyn unmp_link::connection::ConnectionDriver + core::marker::Send`
   = help: the following other types implement trait `core::fmt::Debug`:
             (dyn Any + 'static)
             (dyn Any + Sync + core::marker::Send + 'static)
             (dyn Any + core::marker::Send + 'static)
             (dyn unmp_link::connection::ConnectionDriver + 'static)
             (dyn unmp_link::listener::ListenerDriver + 'static)
   = note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0277`.
error: could not compile `unmp-net` due to 2 previous errors
warning: build failed, waiting for other jobs to finish...

rise0chen avatar Apr 24 '22 10:04 rise0chen

You need to implement Debug for dyn ConnectionDriver + Send, which in this usage acts as a distinct type from dyn ConnectionDriver.

compiler-errors avatar Apr 24 '22 17:04 compiler-errors

I can probably implement a better error message for this, though...

compiler-errors avatar Apr 24 '22 22:04 compiler-errors

I think it should auto implement Debug for both dyn ConnectionDriver + Send and dyn ConnectionDriver + !Send.

rise0chen avatar Apr 25 '22 01:04 rise0chen

@rise0chen, I think that would be a backwards-incompatible change with current behavior, because then these impls would overlap:

trait Bar {}

trait Foo {}

impl Foo for dyn Bar + Send {}

impl Foo for dyn Bar {}

compiler-errors avatar Apr 25 '22 01:04 compiler-errors

impl Foo for dyn Bar + Send {} have a High priority. impl Foo for dyn Bar {} have a Low priority. And, dyn Bar + !Send auto impl Foo by impl Foo for dyn Bar {}

rise0chen avatar Apr 25 '22 01:04 rise0chen

I think the problem here is that dyn A+B isn't a subset of dyn A. They are distinct types. This is different from trait bounds, where T: A+B is a subset of T: A. For trait bounds, we can implement something for A and expect it to be implemented for A+B; or if we want to have a different implementation for A+B, we have specialization for that. We probably need to overhaul the entire dyn type system to make it work in the way you want.

wwylele avatar Apr 25 '22 02:04 wwylele

I think it is a similar problem.

#[async_trait(?Send)]
pub trait ListenerDriver {
    async fn accept(&mut self) -> Result<Connection, RecvError>;
}

#[async_trait]
impl ListenerDriver for Server {
    async fn accept(&mut self) -> Result<Connection, RecvError> {...}
}
error[E0053]: method `accept` has an incompatible type for trait
  --> unmp-link-udp\src\server.rs:86:5
   |
86 |     async fn accept(&mut self) -> Result<Connection, RecvError> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait `Future<Output = Result<unmp_link::connection::Connection, unmp_link::error::RecvError>>`, found trait `Future<Output = Result<unmp_link::connection::Connection, unmp_link::error::RecvError>> + Send`
   |
   = note: expected fn pointer `fn(&'life0 mut server::Server) -> Pin<Box<(dyn Future<Output = Result<unmp_link::connection::Connection, unmp_link::error::RecvError>> + 'async_trait)>>`
              found fn pointer `fn(&'life0 mut server::Server) -> Pin<Box<(dyn Future<Output = Result<unmp_link::connection::Connection, unmp_link::error::RecvError>> + Send + 'async_trait)>>`

For more information about this error, try `rustc --explain E0053`.
error: could not compile `unmp-link-udp` due to previous error

rise0chen avatar Apr 25 '22 07:04 rise0chen

CC #119338 which would fix this I think.

fmease avatar Jan 24 '24 13:01 fmease