rust-lang / rust

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

Recursive type of infinite size is undetected until MIR optimiziations #81867

Open memoryruins opened 3 years ago

memoryruins commented 3 years ago
#![allow(incomplete_features)]
#![feature(generic_associated_types)]

trait Trait {
    type Type<T>;
}

impl Trait for u8 {
    type Type<T> = T;
}

struct S<T: Trait>(Option<T::Type<Self>>);

fn main() {
    S::<u8>(None); // this line and `cargo build` required for a cycle error
}

I expected to see this happen:

An error about a cycle, overflowing requirements, or recursive type of infinite size with a diagnostic underlining the definition of S and usage S::<u8>(None);

Instead, this happened:

A cycle is detected only when optimizing MIR for main, thus this goes uncaught during cargo check. The diagnostic only underlines the function name.

error[E0391]: cycle detected when computing layout of `S<u8>`
   |
   = note: ...which requires computing layout of `std::option::Option<S<u8>>`...
   = note: ...which again requires computing layout of `S<u8>`, completing the cycle
note: cycle used when optimizing MIR for `main`
  --> src\main.rs:14:1
   |
14 | fn main() {
   | ^^^^^^^

Meta

rustc --version --verbose:

rustc 1.52.0-nightly (a73c2e555 2021-02-06)
binary: rustc
commit-hash: a73c2e555c26ef0c8b98c91c97a7d24b7017267f
commit-date: 2021-02-06
host: x86_64-pc-windows-msvc
release: 1.52.0-nightly
LLVM version: 11.0.1
SkiFire13 commented 3 years ago

This isn't exclusive to GATs, the following code produces the same bug on stable:

trait Trait<T> {
    type Type;
}

impl<T> Trait<T> for u8 {
    type Type = T;
}

struct S<T: Trait<Self>>(Option<T::Type>);

fn main() {
    S::<u8>(None); // this line and `cargo build` required for a cycle error
}
jyn514 commented 3 years ago

If you get rid of Self, I can reproduce at least as far back as 1.22.0 (error with rustc, no error with rustc --emit=metadata).

trait Trait<T> {
    type Type;
}

impl<T> Trait<T> for u8 {
    type Type = T;
}

struct S<T: Trait<S<T>>>(Option<T::Type>);

fn main() {
    S::<u8>(None); // this line and `cargo build` required for a cycle error
}