Home > OS >  Is it possible to instantiate new types using const generics in Rust?
Is it possible to instantiate new types using const generics in Rust?

Time:06-25

I am no expert in const generics but I've tried a couple of different approaches, all with issues, when trying out new type instantiations that involve operating on const generics, for example: when trying to increment base in this const generic struct from K to K 1.

// Given a Base<K> return a Base<K 1>
pub struct Base<const K:u32> {}
pub const fn base_bump<const K: u32, const L: u32>(b: Base<K>,) -> Base<L> {
    const L : u32 = K   1;
    Base::<L> {}
}

Error :

error[E0401]: can't use generic parameters from outer function
 --> src/main.rs:5:20
  |
2 | pub const fn base_bump<const K: u32, const L: u32>(
  |                              - const parameter from outer function
...
5 |     const l: u32 = K   1;
  |                    ^ use of generic parameter from outer function

For more information about this error, try `rustc --explain E0401`.
error: could not compile `playground` due to previous error

my understanding is that the current state of const generics refuses to instantiate new const generic's from other const genericss because const generics are types before being values. IOW, K in

fn foo<const K: u32> () {}

is a type rather than a usual const value defined by const K : u32 = 1; Although I will strongly mention here that the error messages aren't pointing the rational behind it.

Another issue arises when we try to do it like this:

pub struct Base<const K:u32> {}
// Given a Base<K> return a Base<K 1>
impl<const K : u32, const L: u32> Base<K> {
    pub fn base_bump(&self) -> Base<L> {
        todo!()
    }
}

Error:

error[E0207]: the const parameter `L` is not constrained by the impl trait, self type, or predicates
 --> src/lib.rs:3:27
  |
3 | impl<const K : u32, const L: u32> Base<K> {
  |                           ^ unconstrained const parameter
  |
  = note: expressions using a const parameter must map each value to a distinct output value
  = note: proving the result of expressions other than the parameter are unique is not supported

Is there any way to achieve what I am trying to do here or should I abandon const generics and use a regular field to define the base here?

CodePudding user response:

my understanding is that the current state of const generics refuses to instantiate new const generic's from other const genericss because const generics are types before being values

This is not true, but there are multiple issues with your code.

First, as the compiler is pointing out, the const L inside the function cannot refer to the function's generic parameter K. This is because consts are compiled separately, even if inside a function (the only difference is being inaccessible to code outside the function, i.e. scoping).

You should embed the computation:

pub const fn base_bump<const K: u32, const L: u32>(b: Base<K>) -> Base<L> {
    Base::<{ K   1 }> {}
}

But this still have multiple problems. First, you're declaring you're returning Base with L chosen by the caller, but you are actually returning a constant K 1 and not L. You need to declare the function like:

pub const fn base_bump<const K: u32>(b: Base<K>) -> Base<{ K   1 }> {
    Base::<{ K   1 }> {}
}

But this errors with:

error: generic parameters may not be used in const operations
 --> src/lib.rs:2:74
  |
2 | pub const fn base_bump<const K: u32, const L: u32>(b: Base<K>) -> Base<{ K   1 }> {
  |                                                                          ^ cannot perform const operation using `K`
  |
  = help: const parameters may only be used as standalone arguments, i.e. `K`

error: generic parameters may not be used in const operations
 --> src/lib.rs:3:14
  |
3 |     Base::<{ K   1 }> {}
  |              ^ cannot perform const operation using `K`
  |
  = help: const parameters may only be used as standalone arguments, i.e. `K`

Because this thing requires #![feature(generic_const_exprs)]. With it it works, but raises a warning:

warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
 --> src/lib.rs:1:12
  |
1 | #![feature(generic_const_exprs)]
  |            ^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(incomplete_features)]` on by default
  = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information

See this answer of mine for why this feature is especially hard.

  • Related