Overflow evaluating the requirement for associated type of type parameter

Context: I'm trying to write a generic AST parameterized over the "compiler pass", so that the stored data can change between passes (i.e., trees-that-grow style). I ran into an issue when trying to get the AST to implement Debug.

Here's a minimal reproduction of the issue (playground link):

use std::fmt::Debug;

#[derive(Debug)]
struct Node<T: HasChild> {
    child: Option<T::Child>,
}

trait HasChild {
    type Child: Debug;
}

impl HasChild for () {
    type Child = Box<Node<()>>;
}
error[E0275]: overflow evaluating the requirement `Node<()>: Debug`
  --> src/main.rs:13:18
   |
13 |     type Child = Box<Node<()>>;
   |                  ^^^^^^^^^^^^^
   |
   = note: required for `Box<Node<()>>` to implement `Debug`
note: required by a bound in `HasChild::Child`
  --> src/main.rs:9:17
   |
9  |     type Child: Debug;
   |                 ^^^^^ required by this bound in `HasChild::Child`

I also tried moving the trait bound from the associated type to the trait implementation, but this just pushes the error to the use site (playground link):

fn node_debug(x: Node<()>) {
    println!("{x:?}")
}

struct Node<T: HasChild> {
    child: Option<T::Child>,
}

impl<T> Debug for Node<T>
where
    T: HasChild,
    T::Child: Debug,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        todo!()
    }
}

trait HasChild {
    type Child;
}

impl HasChild for () {
    type Child = Box<Node<()>>;
}
error[E0275]: overflow evaluating the requirement `Node<()>: Debug`
   --> src/main.rs:4:15
    |
4   |     println!("{x:?}")
    |               ^^^^^
    |
    = note: required for `Box<Node<()>>` to implement `Debug`
    = note: 1 redundant requirement hidden
    = note: required for `Node<()>` to implement `Debug`

Any way that I can work around this?

You could implement Debug manually rather than deriving it:

struct Node<T: HasChild> {
    child: Option<T::Child>,
}

impl<T: HasChild> Debug for Node<T> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Node")
         .field("child", &self.child)
         .finish()
    }
}
2 Likes

Ohh, the issue was the #[derive(Debug)] adding an extra Debug bound on the associated type when it wasn't necessary. I think I can still get away with using a derive by using the derivative crate instead to weaken the trait bound.

Thank you for the help!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.