Skip to content

Commit 48cfb78

Browse files
committed
Rewriting
1 parent 10b4241 commit 48cfb78

File tree

3 files changed

+110
-39
lines changed

3 files changed

+110
-39
lines changed

src/const-generics.md

Lines changed: 95 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ A const argument in a [path] specifies the const value to use for that item.
66

77
r[const-generics.argument.type]
88
The argument must be a [const expression] of the type ascribed to the const
9-
parameter.
9+
parameter.
1010

1111
r[items.generics.const.type-ambiguity]
1212
When there is ambiguity if a generic argument could be resolved as either a
@@ -47,27 +47,106 @@ fn generic<const B: bool>() {
4747
}
4848
```
4949

50-
r[items.generics.const.standalone]
51-
As a further restriction, const parameters may only appear as a standalone
52-
argument inside of a [type] or [array repeat expression]. In those contexts,
53-
they may only be used as a single segment [path expression], possibly inside a
54-
[block] (such as `N` or `{N}`). That is, they cannot be combined with other
50+
r[const-generics.kinds]
51+
There are three kinds of arguments to a const parameter:
52+
1. Standalone const parameters
53+
2. Inferred consts
54+
3. Arbitrary concrete expressions
55+
56+
r[const-generics.standalone]
57+
## Standalone const parameters
58+
59+
A const parameter can only be used in a const argument if it is a standalone usage.
60+
The argument must be *only* a usage of a const parameter and can be wrapped
61+
in at most one level of braces. That is, they cannot be combined with other
5562
expressions.
63+
```rust
64+
// Examples of standalone uses of const parameters
65+
66+
fn foo<const N: usize>() {
67+
let a: [u8; N] = [10; N];
68+
let b: [u8; { N }] = a;
69+
foo::<N>();
70+
foo::<{ N }>();
71+
}
72+
```
73+
74+
Here `a` has type `[u8; N]`, an array with a length of `N`, referring to `foo`'s const parameter.
5675

5776
```rust,compile_fail
58-
// Examples where const parameters may not be used.
77+
// Examples of non-standalone uses of const parameters
5978
60-
// Not allowed to combine in other expressions in types, such as the
61-
// arithmetic expression in the return type here.
62-
fn bad_function<const N: usize>() -> [u8; {N + 1}] {
63-
// Similarly not allowed for array repeat expressions.
64-
[1; {N + 1}]
79+
fn foo<const N: usize>() {
80+
let a: [u8; {{ N }}] = [10; (N)];
81+
foo::<{{ N }}>();
82+
foo::<(N)>();
6583
}
6684
```
6785

68-
The const expression must be a [block expression][block]
69-
(surrounded with braces) unless it is a single path segment (an [IDENTIFIER])
70-
or a [literal] (with a possibly leading `-` token).
86+
r[const-generics.inferred]
87+
## Inferred consts
88+
89+
r[const-generics.inferred.syntax]
90+
```grammar,types
91+
@root InferredConst -> `_`
92+
```
93+
94+
The inferred const asks the compiler to infer the const if possible based on
95+
the surrounding information available.
96+
97+
It cannot be used in item signatures.
98+
99+
It is often used in repeat expressions:
100+
```rust
101+
fn make_array() -> [u32; 2] {
102+
[Default::default(); _]
103+
}
104+
```
105+
106+
r[const-generics.concrete-expr]
107+
## Concrete expressions
108+
109+
Most const expressions are allowed as const arguments:
110+
```rust
111+
// Example of a concrete expressions as an argument
112+
113+
fn make_array() -> [u8; 1 + 10 / 2] {
114+
[1; 6]
115+
}
116+
```
117+
118+
r[const-generics.concrete-expr.limitations]
119+
There are a few limitations about what expressions are allowed:
120+
1. Generic parameters may not be used
121+
2. In-scope where clauses may not be used
122+
3. Must be wrapped in braces in some cases
123+
124+
```rust,compile_fail
125+
// Examples where expressions may not be used as they use generic parameters.
126+
127+
// Not allowed in the const argument for an arrays length
128+
fn bad_function<const N: usize>() -> [u8; N + 1] {
129+
// Similarly not allowed for array repeat expressions' count argument.
130+
[1; N + 1]
131+
}
132+
133+
// Using type parameters is also disallowed
134+
fn type_parameters_disallowed<T>(_: [u8; size_of::<T>()]) {}
135+
```
136+
137+
```rust,compile_fail
138+
// Example where an expression may not be used as it depends on an in-scope
139+
// where clause
140+
141+
fn bad_function(_: [u8; { let a: [u8]; 1 }])
142+
where
143+
for<'a> [u8]: Sized, {}
144+
```
145+
146+
The const expression must be a [block expression][block](surrounded with braces) unless it's:
147+
- a single path segment (an [IDENTIFIER])
148+
- a [literal] (with a possibly leading `-` token)
149+
- an array length or repeat expression count
71150

72151
> [!NOTE]
73152
> This syntactic restriction is necessary to avoid requiring infinite lookahead when parsing an expression inside of a type.
@@ -92,4 +171,4 @@ fn example() {
92171
[block]: ../expressions/block-expr.md
93172
[const expression]: ../const_eval.md#constant-expressions
94173
[literal]: ../expressions/literal-expr.md
95-
[path]: ../paths.md
174+
[path]: ../paths.md

src/items/generics.md

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -67,36 +67,26 @@ The only allowed types of const parameters are `u8`, `u16`, `u32`, `u64`, `u128`
6767
`i8`, `i16`, `i32`, `i64`, `i128`, `isize`, `char` and `bool`.
6868

6969
r[items.generics.const.usage]
70-
Const parameters can be used anywhere a [const item] can be used, with the
71-
exception that when used in a [type] or [array repeat expression], it must be
72-
standalone (as described below). That is, they are allowed in the following
73-
places:
74-
75-
1. As an applied const to any type which forms a part of the signature of the
76-
item in question.
77-
2. As part of a const expression used to define an [associated const], or as a
78-
parameter to an [associated type].
79-
3. As a value in any runtime expression in the body of any functions in the
80-
item.
81-
4. As a parameter to any type used in the body of any functions in the item.
82-
5. As a part of the type of any fields in the item.
70+
Const parameters can be used anywhere in expression position, or as a const argument[^1].
71+
Uses of const parameters must take place inside the item defining it, and not within
72+
an inner item that inhibits access to outer generic parameters.
8373

8474
```rust
8575
// Examples where const generic parameters can be used.
8676

8777
// Used in the signature of the item itself.
8878
fn foo<const N: usize>(arr: [i32; N]) {
89-
// Used as a type within a function body.
79+
// Used within a type within a function body.
9080
let x: [i32; N];
91-
// Used as an expression.
81+
// Used within an expression.
9282
println!("{}", N * 2);
9383
}
9484

95-
// Used as a field of a struct.
85+
// Used within a field of a struct.
9686
struct Foo<const N: usize>([i32; N]);
9787

9888
impl<const N: usize> Foo<N> {
99-
// Used as an associated constant.
89+
// Used within an associated constant.
10090
const CONST: usize = N * 4;
10191
}
10292

@@ -105,13 +95,14 @@ trait Trait {
10595
}
10696

10797
impl<const N: usize> Trait for Foo<N> {
108-
// Used as an associated type.
98+
// Used within an associated type.
10999
type Output = [i32; N];
110100
}
111101
```
112102

113103
```rust,compile_fail
114-
// Examples where const generic parameters cannot be used.
104+
// Examples where const generic parameters cannot be used as the uses are
105+
// within an inner item that inhibits access to outer generic parameters.
115106
fn foo<const N: usize>() {
116107
// Cannot use in item definitions within a function body.
117108
const BAD_CONST: [usize; N] = [1; N];
@@ -124,8 +115,6 @@ fn foo<const N: usize>() {
124115
}
125116
```
126117

127-
There are limitations around how a const parameter can be used within a const argument ([const generics]).
128-
129118
r[items.generics.const.variance]
130119
Unlike type and lifetime parameters, const parameters can be declared without
131120
being used inside of a parameterized item, with the exception of
@@ -200,6 +189,8 @@ struct Foo<#[my_flexible_clone(unbounded)] H> {
200189
}
201190
```
202191

192+
[^1]: There are limitations around how a const parameter can be used within a const argument ([const generics]).
193+
203194
[array repeat expression]: ../expressions/array-expr.md
204195
[arrays]: ../types/array.md
205196
[slices]: ../types/slice.md
@@ -230,4 +221,4 @@ struct Foo<#[my_flexible_clone(unbounded)] H> {
230221
[type aliases]: type-aliases.md
231222
[type]: ../types.md
232223
[unions]: unions.md
233-
[value namespace]: ../names/namespaces.md
224+
[value namespace]: ../names/namespaces.md

src/patterns.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -973,7 +973,8 @@ r[patterns.const.exhaustive]
973973

974974
r[patterns.const.generic]
975975
In particular, the value of `C` must be known at pattern-building time (which is pre-monomorphization).
976-
This means that associated consts that involve generic parameters cannot be used as patterns.
976+
This means that associated consts that involve generic parameters cannot be used as patterns and neither
977+
can uses of const parameters.
977978

978979
r[patterns.const.translation]
979980
After ensuring all conditions are met, the constant value is translated into a pattern, and now behaves exactly as-if that pattern had been written directly.

0 commit comments

Comments
 (0)