Why does a trait bound of an associated type cause an evaluation overflow when the bound is guaranteed to always hold?

Viewed 94

I have a generic extensible AST:

pub trait Schema: Clone {
    type Expr: Clone;
}

#[derive(Clone)]
pub enum Expr<S: Schema> {
    IntLiteral,
    Add(Box<S::Expr>, Box<S::Expr>),
}

#[derive(Clone)]
struct ParserSchema;
impl Schema for ParserSchema {
    type Expr = Expr<ParserSchema>;
}

pub fn main() {
    type ParserExpr = <ParserSchema as Schema>::Expr;
    let expr: ParserExpr = ParserExpr::IntLiteral;
    let e = expr.clone();
}

When I compile this piece of code (Rust playground), I get the following compiler error:

error[E0275]: overflow evaluating the requirement `Expr<ParserSchema>: Clone`
  --> src/main.rs:14:5
   |
14 |     type Expr = Expr<ParserSchema>;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
note: required by a bound in `Schema::Expr`
  --> src/main.rs:2:16
   |
2  |     type Expr: Clone;
   |                ^^^^^ required by this bound in `Schema::Expr`

If I manually implement the Clone trait for Expr (Rust playground), it compiles without a hitch:

impl<S: Schema> Clone for Expr<S> {
    fn clone(&self) -> Self {
        match self {
            Expr::IntLiteral => Expr::IntLiteral,
            Expr::Add(ref lhs, ref rhs) => Expr::Add(lhs.clone(), rhs.clone()),
        }
    }
}

Theoretically, #[derive(Clone)] and the manual implementation of Clone should behave identically. However, if I look at the generated code for #[derive(Clone)], I see the following (cleaned up for readability):

impl<S: Clone + Schema> Clone for Expr<S>
where
    S::Expr: Clone,
{
    fn clone(&self) -> Expr<S> {
        todo!("omitted")
    }
}

The where S::Expr: Clone bound seems to be the culprit; if I remove it, the example compiles successfully. However, I do not understand why this where clause would cause an evaluation overflow. If S: Schema, then S::Expr: Clone is guaranteed to hold. What makes rustc error with an evaluation overflow when adding a clause that is guaranteed to always hold?

0 Answers
Related