The trait bound `X: std::fmt::Debug` is not satisfied


#1

Hello,

I am trying to play with the following code snipped (https://is.gd/YqbNQu)

pub trait NodeRef : Copy + Sized {
        type Error : error::Error;
}

#[derive(Debug)]
pub struct Error<NodeRefType> where NodeRefType : NodeRef {
        kind : ErrorKind<NodeRefType>,
}

#[derive(Debug)]
enum ErrorKind<NodeRefType> where NodeRefType : NodeRef {
        NodeRefError(<NodeRefType as NodeRef>::Error),
}

impl<NodeRefType> fmt::Display for Error<NodeRefType> where NodeRefType : NodeRef {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                match self.kind {
                        ErrorKind::NodeRefError(ref err) => write!(f, "Referenced Node Error: {}", err),
                }
        }
}

impl<NodeRefType> error::Error for Error<NodeRefType> where NodeRefType : NodeRef {
        fn description(&self) -> &str {
                match self.kind {
                        ErrorKind::NodeRefError(ref err) => err.description(),
                }
        }
        fn cause(&self) -> Option<&error::Error> {
                match self.kind {
                        ErrorKind::NodeRefError(ref err) => Some(err),
                }
        }
}

And I get the following error:

31 | impl<NodeRefType> error::Error for Error<NodeRefType> where NodeRefType : NodeRef {
   |                   ^^^^^^^^^^^^ the trait `std::fmt::Debug` is not implemented for `NodeRefType`
   |
   = help: consider adding a `where NodeRefType: std::fmt::Debug` bound
   = note: required because of the requirements on the impl of `std::fmt::Debug` for `Error<NodeRefType>`
   = note: required by `std::error::Error`

And the question is the following. I can not understand why does it want NodeRefType following std::fmt::Debug trait. NodeRefType is not contained by Error directly. Instead only NodeRefType::Error is used (that is of Error trait and follows Debug trait).


#2

I believe this is a bug in #[derive(Debug)] - it’s adding a Debug bound to the type parameter of ErrorKind even though it should only be on NodeRefType::Error.

You may just want to manually implement Debug.


#3

If it is a bug, will this behavior be fixed?


#4

I don’t think it will be fixed. In particular, looking at the definition of struct Error during macro expansion it is impossible to tell that the “right” bound is NodeRefType::Error: Debug.

Instead the derivative crate provides alternative, customizable implementations of deriving the bulitin traits. See https://mcarton.github.io/rust-derivative/Debug.html#custom-bound. It gives you a way to help the compiler by handwriting the correct bound for the Debug impl.

It is a procedural macro and will be stabilized in Rust 1.15 in February.

#![feature(proc_macro)]

#[macro_use]
extern crate derivative;

#[derive(Derivative)]
#[derivative(Debug(bound = "NodeRefType::Error: Debug"))]
pub struct Error<NodeRefType> where NodeRefType : NodeRef {
    kind : ErrorKind<NodeRefType>,
}

#[derive(Derivative)]
#[derivative(Debug(bound = "NodeRefType::Error: Debug"))]
enum ErrorKind<NodeRefType> where NodeRefType : NodeRef {
    NodeRefError(<NodeRefType as NodeRef>::Error),
}

#5

@dtolnay why isn’t it? It seems like the plugin should be able to figure it out just from looking at the definition of the variant field as <NodeRefType as NodeRef>::Error?


#6

For #[derive(Debug)] enum ErrorKind sure - but not for #[derive(Debug)] struct Error. The only other thing it could do for struct Error is ErrorKind<NodeRefType>: Debug but we tried that in Serde and it caused more problems than it solved. See serde-rs/serde#435, serde-rs/serde#436, serde-rs/serde#441, serde-rs/serde#443. We decided the best bet was to generate predictable, obvious bounds and provide a simple way to handwrite them in the 1% of edge cases which is what derivative provides.


#7

Where can I find default implementation of Debug for enums from std::?
I see things like std::fmt::DebugStruct (https://doc.rust-lang.org/std/fmt/struct.DebugStruct.html), but nothing special to enums.


#8

Maybe this (part of core rust): https://github.com/rust-lang/rust/blob/467a7f049bac0386097c6cd2c80966c8d7453ce8/src/libsyntax_ext/deriving/debug.rs