Skip to content

Regression: cycle detected when coherence checking all impls of trait core::convert::From #156296

@nazar-pc

Description

@nazar-pc

I tried this code:

#![feature(const_convert, const_trait_impl, generic_const_exprs)]
#![expect(incomplete_features, reason = "generic_const_exprs")]

pub mod b {
    pub struct WrapperB([u8; WrapperB::SIZE]);

    impl From<WrapperB> for [u8; WrapperB::SIZE] {
        fn from(value: WrapperB) -> Self {
            <[u8; WrapperB::SIZE]>::from(value.0)
        }
    }

    impl WrapperB {
        pub const SIZE: usize = 32;
    }
}
pub mod a {
    pub struct WrapperA([u8; WrapperA::SIZE]);

    impl From<[u8; WrapperA::SIZE]> for WrapperA {
        fn from(value: [u8; WrapperA::SIZE]) -> Self {
            WrapperA(value)
        }
    }

    impl WrapperA {
        pub const SIZE: usize = usize::from(1u8);
    }
}

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=bdf3caab9574ab358c34f36083e8d4f9

I expected to see this happen: Compiles without errors

Instead, this happened:

Details
error[E0391]: cycle detected when coherence checking all impls of trait `core::convert::From`
   --> /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/convert/mod.rs:588:1
    |
588 | pub const trait From<T>: Sized {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
note: ...which requires building specialization graph of trait `core::convert::From`...
   --> src/lib.rs:20:20
    |
 20 |     impl From<[u8; WrapperA::SIZE]> for WrapperA {
    |                    ^^^^^^^^^^^^^^
note: ...which requires evaluating type-level constant...
   --> src/lib.rs:20:20
    |
 20 |     impl From<[u8; WrapperA::SIZE]> for WrapperA {
    |                    ^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `a::<impl at src/lib.rs:20:5: 20:49>::{constant#0}`...
   --> src/lib.rs:20:20
    |
 20 |     impl From<[u8; WrapperA::SIZE]> for WrapperA {
    |                    ^^^^^^^^^^^^^^
note: ...which requires checking if `a::<impl at src/lib.rs:20:5: 20:49>::{constant#0}` is a trivial const...
   --> src/lib.rs:20:20
    |
 20 |     impl From<[u8; WrapperA::SIZE]> for WrapperA {
    |                    ^^^^^^^^^^^^^^
note: ...which requires building MIR for `a::<impl at src/lib.rs:20:5: 20:49>::{constant#0}`...
   --> src/lib.rs:20:20
    |
 20 |     impl From<[u8; WrapperA::SIZE]> for WrapperA {
    |                    ^^^^^^^^^^^^^^
note: ...which requires checking if `a::<impl at src/lib.rs:26:5: 26:18>::SIZE` is a trivial const...
   --> src/lib.rs:27:9
    |
 27 |         pub const SIZE: usize = usize::from(1);
    |         ^^^^^^^^^^^^^^^^^^^^^
note: ...which requires building MIR for `a::<impl at src/lib.rs:26:5: 26:18>::SIZE`...
   --> src/lib.rs:27:9
    |
 27 |         pub const SIZE: usize = usize::from(1);
    |         ^^^^^^^^^^^^^^^^^^^^^
note: ...which requires match-checking `a::<impl at src/lib.rs:26:5: 26:18>::SIZE`...
   --> src/lib.rs:27:9
    |
 27 |         pub const SIZE: usize = usize::from(1);
    |         ^^^^^^^^^^^^^^^^^^^^^
note: ...which requires type-checking `a::<impl at src/lib.rs:26:5: 26:18>::SIZE`...
   --> src/lib.rs:27:9
    |
 27 |         pub const SIZE: usize = usize::from(1);
    |         ^^^^^^^^^^^^^^^^^^^^^
    = note: ...which again requires coherence checking all impls of trait `core::convert::From`, completing the cycle
note: cycle used when checking that `b::<impl at src/lib.rs:7:5: 7:49>` is well-formed
   --> src/lib.rs:7:5
    |
  7 |     impl From<WrapperB> for [u8; WrapperB::SIZE] {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information

Even more confusingly, rearranging modules a and b results in a different error, but it also mentions cycles:

Details
error[E0391]: cycle detected when checking if `a::<impl at src/lib.rs:13:5: 13:18>::SIZE` is a trivial const
   --> src/lib.rs:14:9
    |
 14 |         pub const SIZE: usize = usize::from(1u8);
    |         ^^^^^^^^^^^^^^^^^^^^^
    |
note: ...which requires building MIR for `a::<impl at src/lib.rs:13:5: 13:18>::SIZE`...
   --> src/lib.rs:14:9
    |
 14 |         pub const SIZE: usize = usize::from(1u8);
    |         ^^^^^^^^^^^^^^^^^^^^^
note: ...which requires match-checking `a::<impl at src/lib.rs:13:5: 13:18>::SIZE`...
   --> src/lib.rs:14:9
    |
 14 |         pub const SIZE: usize = usize::from(1u8);
    |         ^^^^^^^^^^^^^^^^^^^^^
note: ...which requires type-checking `a::<impl at src/lib.rs:13:5: 13:18>::SIZE`...
   --> src/lib.rs:14:9
    |
 14 |         pub const SIZE: usize = usize::from(1u8);
    |         ^^^^^^^^^^^^^^^^^^^^^
note: ...which requires coherence checking all impls of trait `core::convert::From`...
   --> /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/convert/mod.rs:588:1
    |
588 | pub const trait From<T>: Sized {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires building specialization graph of trait `core::convert::From`...
   --> src/lib.rs:7:20
    |
  7 |     impl From<[u8; WrapperA::SIZE]> for WrapperA {
    |                    ^^^^^^^^^^^^^^
note: ...which requires evaluating type-level constant...
   --> src/lib.rs:7:20
    |
  7 |     impl From<[u8; WrapperA::SIZE]> for WrapperA {
    |                    ^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `a::<impl at src/lib.rs:7:5: 7:49>::{constant#0}`...
   --> src/lib.rs:7:20
    |
  7 |     impl From<[u8; WrapperA::SIZE]> for WrapperA {
    |                    ^^^^^^^^^^^^^^
note: ...which requires checking if `a::<impl at src/lib.rs:7:5: 7:49>::{constant#0}` is a trivial const...
   --> src/lib.rs:7:20
    |
  7 |     impl From<[u8; WrapperA::SIZE]> for WrapperA {
    |                    ^^^^^^^^^^^^^^
note: ...which requires building MIR for `a::<impl at src/lib.rs:7:5: 7:49>::{constant#0}`...
   --> src/lib.rs:7:20
    |
  7 |     impl From<[u8; WrapperA::SIZE]> for WrapperA {
    |                    ^^^^^^^^^^^^^^
    = note: ...which again requires checking if `a::<impl at src/lib.rs:13:5: 13:18>::SIZE` is a trivial const, completing the cycle
note: cycle used when building MIR for `a::WrapperA::0::{constant#0}`
   --> src/lib.rs:5:30
    |
  5 |     pub struct WrapperA([u8; WrapperA::SIZE]);
    |                              ^^^^^^^^^^^^^^
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information

Meta

rustc --version --verbose:

rustc 1.97.0-nightly (365c0e1d7 2026-05-06)
binary: rustc
commit-hash: 365c0e1d7a614ca94cb48431dcd2bc6d3b645db1
commit-date: 2026-05-06
host: x86_64-unknown-linux-gnu
release: 1.97.0-nightly
LLVM version: 22.1.4

The first version that fails is nightly-2026-05-04:

rustc 1.97.0-nightly (ad3a598ca 2026-05-03)
binary: rustc
commit-hash: ad3a598ca4bc7c68bcbbce3e0d3be9a7618df190
commit-date: 2026-05-03
host: x86_64-unknown-linux-gnu
release: 1.97.0-nightly
LLVM version: 22.1.4

The last version that works correctly is nightly-2026-05-03:

rustc 1.97.0-nightly (20de910db 2026-05-02)
binary: rustc
commit-hash: 20de910db49d3476ccf49ea79a4b22e2b5dface0
commit-date: 2026-05-02
host: x86_64-unknown-linux-gnu
release: 1.97.0-nightly
LLVM version: 22.1.4

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.F-const_trait_impl`#![feature(const_trait_impl)]`F-generic_const_exprs`#![feature(generic_const_exprs)]`I-cycleIssue: A query cycle occurred while none was expectedT-typesRelevant to the types team, which will review and decide on the PR/issue.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions