Skip to content

"cycle detected when building an abstract representation..." issue #53

Open
@fubupc

Description

@fubupc

This is a problem when implementing a bitfield macro in Rust.

pub trait Bits {
    const BITS: usize; // How many bits this field has

    type Underlying; // Minimum underlying uint (u8, u16, ...) to store this field

    fn from_arbint(from: arbitrary_int::UInt<Self::Underlying, { Self::BITS }>) -> Self;
}

This code uses an arbitrary precision integer library: arbitrary-int. Trait Bits is used to describe:

  • How many bits this field has.
  • Minimum underlying uint type to store this field, like u8, u16, .. etc.
  • How to convert an arbitrary_int::UInt<T, BITS> to this field.
    For example, for a bool type:
impl Bits for bool {
    const BITS: usize = 1;

    type Underlying = u8;

    fn from_arbint(from: arbitrary_int::UInt<Self::Underlying, { Self::BITS }>) -> Self {
        from.value() == 1
    }
}

For array type it becomes a bit more complicated:

// Used to calculate the minimun uint type to store bits 
pub trait CalcUint {
    type Uint;
}
impl CalcUint for [(); 1] {
    type Uint = u8;
}
...
impl CalcUint for [(); 9] {
    type Uint = u16;
}
...
impl<T, const N: usize> Bits for [T; N]
where
    T: Bits + Default + Copy,
    [(); T::BITS * N]: CalcUint,
{
    const BITS: usize = T::BITS * N;

    type Underlying = <[(); T::BITS * N] as CalcUint>::Uint;

    fn from_arbint(from: arbitrary_int::UInt<Self::Underlying, { Self::BITS }>) -> Self {
        todo!()
    }
}

Then the compiler report error at { Self::BITS } in from_arbint:

error[E0391]: cycle detected when building an abstract representation for `<impl at src/lib.rs:53:1: 56:33>::from_arbint::{constant#0}`
  --> src/lib.rs:62:64
   |
62 |     fn from_arbint(from: arbitrary_int::UInt<Self::Underlying, { Self::BITS }>) -> Self {
   |                                                                ^^^^^^^^^^^^^^
   |
note: ...which requires building THIR for `<impl at src/lib.rs:53:1: 56:33>::from_arbint::{constant#0}`...
  --> src/lib.rs:62:64
   |
62 |     fn from_arbint(from: arbitrary_int::UInt<Self::Underlying, { Self::BITS }>) -> Self {
   |                                                                ^^^^^^^^^^^^^^
note: ...which requires type-checking `<impl at src/lib.rs:53:1: 56:33>::from_arbint::{constant#0}`...
  --> src/lib.rs:62:72
   |
62 |     fn from_arbint(from: arbitrary_int::UInt<Self::Underlying, { Self::BITS }>) -> Self {
   |                                                                        ^^^^
   = note: ...which requires evaluating trait selection obligation `[T; N]: Bits`...
   = note: ...which again requires building an abstract representation for `<impl at src/lib.rs:53:1: 56:33>::from_arbint::{constant#0}`, completing the cycle
note: cycle used when checking that `<impl at src/lib.rs:53:1: 56:33>` is well-formed
  --> src/lib.rs:53:1
   |
53 | / impl<T, const N: usize> Bits for [T; N]
54 | | where
55 | |     T: Bits + Default + Copy,
56 | |     [(); T::BITS * N]: CalcUint,
   | |________________________________^
   = 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

Can someone help to explain why is this happening and how to fix it? Thanks!

PS: For complete code: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=a893e99e95aa2a964fa49546a9fbdaaa .
NOTE: The playground does not support random 3rd party library(?), so one need to copy code to local for test/debug.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions