How to derive Debug when one of the types involved doesn't impl Debug?

playground
In the demo below, A doesn't implement Debug, but all B<T> implements Debug, so I expect that all types that uses any B<T> can derive Debug, but it't not true. C<T> wrappes B<T> and derives Debug, but it seems that not all C<T> implements Debug, because D, which uses C<A>, can't derive Debug.
I want to know that is there a way to do something with B, that can recover the ability to derive Debug?

struct A;

struct B<T>(T);

impl<T> Debug for B<T> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        write!(f, "B")
    }
}

#[derive(Debug)]
struct C<T>(B<T>);

#[derive(Debug)]
struct D(C<A>);

You don't.

No. ... Kind of. I know there is some degree of support for specialisation, which might work, but it's unstable and you shouldn't be using it outside of helping test the feature. Unstable features can change or be removed at any time without warning, and aren't subject to backward compatibility guarantees.

If you want to ensure that T doesn't restrict the implementation of Debug for C<T>, then you need to implement Debug yourself. There might be a crate that does this for you, but I'm not aware of one. If you have to do this with a lot of types, you could also try implementing a procedural macro yourself.

1 Like

it's a limitation of the Debug derive macro when generic is involved. the problem is in the C type, not the D type.

because the C type has T as generic parameter, the derive macro expands into something like:

impl<T: Debug> Debug for C<T> {
    //...
}

note the T: Debug bounds, it is there to simplify the derive macro. otherwise, it need to parse every struct fields type to add "perfect" bounds, something like this:

impl<T> Debug for C<T> where B<T>: Debug {
    //...
}

see "perfect derive":


in your example, you can manually derive Debug for the C<T> struct, then the D struct (which is not generic) can be derived without problem.

alternatively, you can use an intermediate type (_C in the following snippet) just for the purpose of derive macro with generics, and use a type alias (or newtype) as the "real" type (the C type alias in the example):

struct A;
struct B<T>(T);
impl<T> Debug for B<T> {
    //...
}

#[derive(Debug)]
struct _C<BT>(BT);
type C<T> = _C<B<T>>;

#[derive(Debug)]
struct D(C<A>);
5 Likes

Thank you for your explaination and solution!