Search code examples
rustsyntaxconst-generics

Why is an empty where constraint needed for a generic constant expression?


I would like to define a struct like this, but the compiler yields an error:

#![feature(generic_const_exprs)]

struct ArInt<const W: usize, const S: bool> {
    iarr: [i32; { (W + 31 + (!S) as usize) / 32 }],
}
error: unconstrained generic constant
 --> src/lib.rs:4:11
  |
4 |     iarr: [i32; { (W + 31 + (!S) as usize) / 32 }],
  |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = help: try adding a `where` bound using this expression: `where [(); { (W + 31 + (!S) as usize) / 32 }]:`

I made the following modification as per the compiler's suggestion and it works:

#![feature(generic_const_exprs)]

struct ArInt<const W: usize, const S: bool>
where
    [(); { (W + 31 + (!S) as usize) / 32 }]:
{
    iarr: [i32; { (W + 31 + (!S) as usize) / 32 }],
}

Can someone explain the where clause's constraint meaning here? It looks weird.


Solution

  • In this context where [(); {(W + 31 + (!S) as usize)/32}]: means more or less: "where [(); {(W + 31 + (!S) as usize)/32}] is a possible type". This makes the allowed values clear from the get go. For example you can't do this:

    let f: ArInt<usize::MAX, true>;
    

    because usize::MAX + 31 would overflow. The where clause makes that constraint visible without you needing to go through the implementation details to see it.