rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
97.92k stars 12.68k forks source link

Overflow when deriving Clone on a struct with a recursive GAT #102580

Open PizzasBear opened 2 years ago

PizzasBear commented 2 years ago

I tried this code:

trait Trait: Clone {
    type Type<T: Clone>: Clone;
}

#[derive(Clone)]
struct Struct<T: Trait>(Option<T::Type<Self>>);

// impl<T: Trait> Clone for Struct<T> {
//     fn clone(&self) -> Self {
//         Self(self.0.clone())
//     }
// }

I expected the derive to happen successfully without issue, like the manual implementation that I commented out.

Instead the derive resulted in an overflow error.

Meta

rustc --version --verbose:

rustc 1.66.0-nightly (57f097ea2 2022-10-01)
binary: rustc
commit-hash: 57f097ea25f2c05f424fc9b9dc50dbd6d399845c
commit-date: 2022-10-01
host: x86_64-unknown-linux-gnu
release: 1.66.0-nightly
LLVM version: 15.0.2
Backtrace

``` error[E0275]: overflow evaluating the requirement `::Type>: Clone` --> src/lib.rs:6:25 | 6 | struct Struct(Option>); | ^^^^^^^^^^^^^^^^^^^^^ | note: required for `Struct` to implement `Clone` --> src/lib.rs:5:10 | 5 | #[derive(Clone)] | ^^^^^ | | | in this derive macro expansion | in this derive macro expansion | ::: /home/user/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/clone.rs:144:1 | 144 | pub macro Clone($item:item) { | --------------- | | | in this expansion of `#[derive(Clone)]` | in this expansion of `#[derive(Clone)]` note: required by a bound in `Trait::Type` --> src/lib.rs:2:18 | 2 | type Type: Clone; | ^^^^^ required by this bound in `Trait::Type` For more information about this error, try `rustc --explain E0275`. ```

wwylele commented 2 years ago

I guess this is related to the existing limitation of derived Clone which blindly applies trait bounds to generic parameters, and generates the following impl block

impl<T: Trait + Clone> Clone for Struct<T> {...}

Note the additional Clone bound on T comparing to the manual implementation, which means not all Struct<T> implements Clone, so it needs to evaluate the bound recursively for Type<T: Clone>