8000 Merge pull request #888 from lcnr/const-generics-update · lu-zero/blog.rust-lang.org@15a0f8a · GitHub
[go: up one dir, main page]

Skip to content

Commit 15a0f8a

Browse files
authored
Merge pull request rust-lang#888 from lcnr/const-generics-update
const generics feature update internals post
2 parents 947d269 + 1ce0a21 commit 15a0f8a

File tree

1 file changed

+129
-0
lines changed

1 file changed

+129
-0
lines changed
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
---
2+
layout: post
3+
title: "Splitting the const generics features"
4+
author: lcnr
5+
description: "Splitting the const generics features"
6+
team: The Const Generics Project Group <https://rust-lang.github.io/project-const-generics/>
7+
---
8+
9+
After the stabilization of the const generics MVP in version 1.51, the const generics project group has continued to
10+
work on const generics. Large parts of this work were gated behind the feature gates `const_generics` and `const_evaluatable_checked`. As time went on, the
11+
`const_generics` feature became fairly useless on its own while the name of
12+
`const_evaluatable_checked` didn't really capture what this feature was intended to do.
13+
14+
To improve this, we have recently removed the features `const_generics`, `lazy_normalization_consts`, and `const_evaluatable_checked`. They have been replaced by `feature(adt_const_params)` and `feature(generic_const_exprs)`.
15+
16+
As there is a lot going on with const generics, here's a quick overview of the new - and preexisting - features and how much still needs to be done for them to get stabilized:
17+
18+
### `feature(adt_const_params)`
19+
20+
On stable, only integers, `char` and `bool` are allowed as the types of const parameters. This feature allows additional types, such as `&'static str` and user defined types.
21+
```rust
22+
#![feature(adt_const_params)]
23+
24+
#[derive(PartialEq, Eq)]
25+
enum ImageFormat {
26+
Rgb8,
27+
Rgba8,
28+
// ...c
29+
}
30+
31+
struct Image<const FORMAT: ImageFormat> {
32+
// ...
33+
}
34+
35+
impl Image<{ ImageFormat::Rgba }> {
36+
fn alpha(&self, pixel: PixelLocation) -> u8 {
37+
// ...
38+
}
39+
}
40+
```
41+
Note that even with this feature, generic const parameter types, such as `struct Foo<T, const N: T> { ... }`, are forbidden.
42+
While allowing such things is desired, it adds additional complications exceeding our current capacity.
43+
44+
There are still two major blockers for stabilization:
45+
46+
The first being the [transition to valtrees](https://github.com/rust-lang/rust/pull/83234). Valtrees are a representation of values as trees with integer nodes, simplifiying the way we interact with more complex types.
47+
48+
Additionally, we have to figure out which types we *even want* to allow as const parameter types. This ties into the discussion
49+
about ["structural match"](https://github.com/rust-lang/rust/issues/74446), which is still ongoing.
50+
51+
While the issues mentioned above are definitely not trivial, it is definitely possible for this to be ready for stabilization in a few months.
52+
53+
### `feature(generic_const_exprs)`
54+
55+
Without any unstable features, const arguments must either be a fully concrete expression or a generic parameter by itself, so constants like `N + 1` are forbidden. With this feature, expressions using generic parameters are possible.
56+
57+
```rust
58+
#![feature(generic_const_exprs)]
59+
60+
fn split_first<T, const N: usize>(arr: [T; N]) -> (T, [T; N - 1]) {
61+
// ...
62+
}
63+
64+
struct BitSet<const SIZE: usize>
65+
where
66+
[u8; (SIZE + 7) / 8]: Sized,
67+
{
68+
storage: [u8; (SIZE + 7) / 8],
69+
}
70+
```
71+
72+
We currently require the user to add bounds asserting that generic constants evaluate successfully. For all constants visible in the API of an item, these bounds are added implicitly.
73+
74+
If the constant expression `expr` of type `Foo` would otherwise not be used in the `where`-clauses or function signature, we add an otherwise irrelevant bound mentioning `expr` to the `where`-clauses of our item. For this one can define a `struct Evaluatable<const N: Foo>;` and use `Evaluatable<{ expr }>:` as a bound. If `expr` is of type `usize` we tend to use `[u8; expr]:`
75+
or `[u8; expr]: Sized` for this. While it is highly likely that we will add a dedicated syntax for these bounds in the future, we are waiting with this until the rest of this feature is more mature.
76+
77+
This feature is still far from being stable and has some [**major** unsolved issues](https://github.com/rust-lang/project-const-generics/blob/master/design-docs/anon-const-substs.md). Especially for constants inside of `where`-bounds there are a lot of subtle bugs and backwards incompatibilities we have to fix before we can even think about how to stabilize this.
78+
79+
### `feature(const_generics_defaults)`
80+
81+
Similar to type parameter defaults, this feature adds the ability to declare default values for const parameters.
82+
83+
```rust
84+
#![feature(const_generics_defaults)]
85+
86+
struct ArrayStorage<T, const N: usize = 2> {
87+
arr: [T; N],
88+
}
89+
90+
impl<T> ArrayStorage<T> {
91+
fn new(a: T, b: T) -> ArrayStorage<T> {
92+
ArrayStorage {
93+
arr: [a, b],
94+
}
95+
}
96+
}
97+
```
98+
To allow type parameter defaults in the same listing as const parameters we also intend to remove the ordering restriction for
99+
type and const parameters, allowing `struct Foo<const N: usize, T = [u32; N]> { ... }`.
100+
101+
This feature is pretty much ready for stabilization and is currently blocked on figuring out any potential edge cases for the
102+
stabilization report.
103+
104+
### `feature(generic_arg_infer)`
105+
106+
While it is already possible to use a wildcard `_` for type arguments inside of bodies, this is not the case for const arguments.
107+
This feature adds this capability for constants.
108+
109+
```rust
110+
#![feature(generic_arg_infer)]
111+
fn array_from<T, U, const N: usize>(arr: [T; N]) -> [U; N]
112+
where
113+
U: From<T>,
114+
{
115+
arr.map(From::from)
116+
}
117+
118+
fn main() {
119+
let x = ["this", "is", "a", "six", "element", "array"];
120+
// using `_` for the parameter `N` lets
121+
// the compiler infer the correct value
122+
let _y = array_from::<_, String, _>(x);
123+
}
124+
```
125+
126+
This feature is not yet ready for stabilization, though there aren't any known big blockers here.
127+
To confidently stabilize this we are probably in need of some large refactorings though, as the current setup
128+
feels fairly fragile in some areas.
129+

0 commit comments

Comments
 (0)
0