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?