I am exploring the use of const generics in Rust. I have constructed the following toy example, which I believe should compile.
#![feature(generic_const_exprs)]
trait A {
const N: usize;
}
trait B: A {
fn f() -> [bool; Self::N];
}
struct S<T> where T: A, [bool; T::N]: Sized {
a: [bool; T::N]
}
impl<T> A for S<T> where T: A, [bool; T::N]: Sized {
const N: usize = T::N;
}
impl<T> B for S<T> where T: A, [bool; T::N]: Sized {
fn f() -> [bool; Self::N] {
panic!()
}
}
struct U;
impl A for U {
const N: usize = 0;
}
fn main() {
println!("{}", S::<U>::N);
}
However, this fails to compile.
error[E0391]: cycle detected when building an abstract representation for <impl at src/main.rs:17:1: 17:19>::f::{constant#0}
--> src/main.rs:18:22
|
18 | fn f() -> [bool; Self::N] {
| ^^^^^^^
|
note: ...which requires building THIR for `<impl at src/main.rs:17:1: 17:19>::f::{constant#0}`...
--> src/main.rs:18:22
|
18 | fn f() -> [bool; Self::N] {
| ^^^^^^^
note: ...which requires type-checking `<impl at src/main.rs:17:1: 17:19>::f::{constant#0}`...
--> src/main.rs:18:22
|
18 | fn f() -> [bool; Self::N] {
| ^^^^^^^
= note: ...which requires evaluating trait selection obligation `S<T>: A`...
= note: ...which again requires building an abstract representation for <impl at src/main.rs:17:1: 17:19>::f::{constant#0}, completing the cycle
note: cycle used when checking that `<impl at src/main.rs:17:1: 17:19>::f` is well-formed
--> src/main.rs:18:5
|
18 | fn f() -> [bool; Self::N] {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
If I remove the impl B for S
, the program compiles and works as expected.
I think I understand the error except for the last implication. Why does evaluating the trait selection obligation S<T>: A
require building a representation for the impl B for S
? It seems to me like S<T>: A
has nothing to do with whether or not S
impls B
.
More generally, is there any way to make this pattern compilable? I would like a trait with a const, a generic type over that trait implementing the trait and using the const in its members, and a function on that generic type using the const.
In case it matters, I am using rust 1.66.0-nightly (8b0c05d9a 2022-10-07).