Skip to content

Commit 50fc162

Browse files
authored
Merge pull request #1835 from BoxyUwU/const-generics-stuff
Document inferred const args (`feature(generic_arg_infer)`)
2 parents c590f78 + b09010d commit 50fc162

File tree

3 files changed

+83
-18
lines changed

3 files changed

+83
-18
lines changed

src/expressions/array-expr.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,18 @@ r[expr.array.length-operand]
3535
The expression after the `;` is called the *length operand*.
3636

3737
r[expr.array.length-restriction]
38-
It must have type `usize` and be a [constant expression], such as a [literal] or a [constant item].
38+
The length operand must either be an [inferred const] or be a [constant expression] of type `usize` (e.g. a [literal] or a [constant item]).
39+
40+
```rust
41+
const C: usize = 1;
42+
let _: [u8; C] = [0; 1]; // Literal.
43+
let _: [u8; C] = [0; C]; // Constant item.
44+
let _: [u8; C] = [0; _]; // Inferred const.
45+
let _: [u8; C] = [0; (((_)))]; // Inferred const.
46+
```
47+
48+
> [!NOTE]
49+
> In an array expression, an [inferred const] is parsed as an [expression][Expression] but then semantically treated as a separate kind of [const generic argument].
3950
4051
r[expr.array.repeat-behavior]
4152
An array expression of this form creates an array with the length of the value of the length operand with each element being a copy of the repeat operand.
@@ -111,8 +122,10 @@ The array index expression can be implemented for types other than arrays and sl
111122
[IndexMut]: std::ops::IndexMut
112123
[Index]: std::ops::Index
113124
[array]: ../types/array.md
125+
[const generic argument]: items.generics.const.argument
114126
[constant expression]: ../const_eval.md#constant-expressions
115127
[constant item]: ../items/constant-items.md
128+
[inferred const]: items.generics.const.inferred
116129
[literal]: ../tokens.md#literals
117130
[memory location]: ../expressions.md#place-expressions-and-value-expressions
118131
[panic]: ../panic.md

src/items/generics.md

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -146,29 +146,55 @@ r[items.generics.const.argument]
146146
A const argument in a [path] specifies the const value to use for that item.
147147

148148
r[items.generics.const.argument.const-expr]
149-
The argument must be a [const expression] of the type ascribed to the const
150-
parameter. The const expression must be a [block expression][block]
151-
(surrounded with braces) unless it is a single path segment (an [IDENTIFIER])
152-
or a [literal] (with a possibly leading `-` token).
149+
The argument must either be an [inferred const] or be a [const expression] of the type ascribed to the const parameter. The const expression must be a [block expression][block] (surrounded with braces) unless it is a single path segment (an [IDENTIFIER]) or a [literal] (with a possibly leading `-` token).
153150

154151
> [!NOTE]
155152
> This syntactic restriction is necessary to avoid requiring infinite lookahead when parsing an expression inside of a type.
156153
157154
```rust
158-
fn double<const N: i32>() {
159-
println!("doubled: {}", N * 2);
160-
}
155+
struct S<const N: i64>;
156+
const C: i64 = 1;
157+
fn f<const N: i64>() -> S<N> { S }
158+
159+
let _ = f::<1>(); // Literal.
160+
let _ = f::<-1>(); // Negative literal.
161+
let _ = f::<{ 1 + 2 }>(); // Constant expression.
162+
let _ = f::<C>(); // Single segment path.
163+
let _ = f::<{ C + 1 }>(); // Constant expression.
164+
let _: S<1> = f::<_>(); // Inferred const.
165+
let _: S<1> = f::<(((_)))>(); // Inferred const.
166+
```
167+
168+
> [!NOTE]
169+
> In a generic argument list, an [inferred const] is parsed as an [inferred type][InferredType] but then semantically treated as a separate kind of [const generic argument].
161170
162-
const SOME_CONST: i32 = 12;
171+
r[items.generics.const.inferred]
172+
Where a const argument is expected, an `_` (optionally surrounding by any number of matching parentheses), called the *inferred const* ([path rules][paths.expr.complex-const-params], [array expression rules][expr.array.length-restriction]), can be used instead. This asks the compiler to infer the const argument if possible based on surrounding information.
163173

164-
fn example() {
165-
// Example usage of a const argument.
166-
double::<9>();
167-
double::<-123>();
168-
double::<{7 + 8}>();
169-
double::<SOME_CONST>();
170-
double::<{ SOME_CONST + 5 }>();
174+
```rust
175+
fn make_buf<const N: usize>() -> [u8; N] {
176+
[0; _]
177+
// ^ Infers `N`.
171178
}
179+
let _: [u8; 1024] = make_buf::<_>();
180+
// ^ Infers `1024`.
181+
```
182+
183+
> [!NOTE]
184+
> An [inferred const] is not semantically an [expression][Expression] and so is not accepted within braces.
185+
>
186+
> ```rust,compile_fail
187+
> fn f<const N: usize>() -> [u8; N] { [0; _] }
188+
> let _: [_; 1] = f::<{ _ }>();
189+
> // ^ ERROR `_` not allowed here
190+
> ```
191+
192+
r[items.generics.const.inferred.constraint]
193+
The inferred const cannot be used in item signatures.
194+
195+
```rust,compile_fail
196+
fn f<const N: usize>(x: [u8; N]) -> [u8; _] { x }
197+
// ^ ERROR not allowed
172198
```
173199
174200
r[items.generics.const.type-ambiguity]
@@ -293,6 +319,7 @@ struct Foo<#[my_flexible_clone(unbounded)] H> {
293319
[block]: ../expressions/block-expr.md
294320
[const contexts]: ../const_eval.md#const-context
295321
[const expression]: ../const_eval.md#constant-expressions
322+
[const generic argument]: items.generics.const.argument
296323
[const item]: constant-items.md
297324
[enumerations]: enumerations.md
298325
[functions]: functions.md
@@ -301,6 +328,7 @@ struct Foo<#[my_flexible_clone(unbounded)] H> {
301328
[generic parameter scopes]: ../names/scopes.md#generic-parameter-scopes
302329
[higher-ranked lifetimes]: ../trait-bounds.md#higher-ranked-trait-bounds
303330
[implementations]: implementations.md
331+
[inferred const]: items.generics.const.inferred
304332
[item declarations]: ../statements.md#item-declarations
305333
[item]: ../items.md
306334
[literal]: ../expressions/literal-expr.md

src/paths.md

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,30 @@ The order of generic arguments is restricted to lifetime arguments, then type
9191
arguments, then const arguments, then equality constraints.
9292

9393
r[paths.expr.complex-const-params]
94-
Const arguments must be surrounded by braces unless they are a
95-
[literal] or a single segment path.
94+
Const arguments must be surrounded by braces unless they are a [literal], an [inferred const], or a single segment path. An [inferred const] may not be surrounded by braces.
95+
96+
```rust
97+
mod m {
98+
pub const C: usize = 1;
99+
}
100+
const C: usize = m::C;
101+
fn f<const N: usize>() -> [u8; N] { [0; N] }
102+
103+
let _ = f::<1>(); // Literal.
104+
let _: [_; 1] = f::<_>(); // Inferred const.
105+
let _: [_; 1] = f::<(((_)))>(); // Inferred const.
106+
let _ = f::<C>(); // Single segment path.
107+
let _ = f::<{ m::C }>(); // Multi-segment path must be braced.
108+
```
109+
110+
```rust,compile_fail
111+
fn f<const N: usize>() -> [u8; N] { [0; _] }
112+
let _: [_; 1] = f::<{ _ }>();
113+
// ^ ERROR `_` not allowed here
114+
```
115+
116+
> [!NOTE]
117+
> In a generic argument list, an [inferred const] is parsed as an [inferred type][InferredType] but then semantically treated as a separate kind of [const generic argument].
96118
97119
r[paths.expr.impl-trait-params]
98120
The synthetic type parameters corresponding to `impl Trait` types are implicit,
@@ -480,10 +502,12 @@ mod without { // crate::without
480502
[`Self` scope]: names/scopes.md#self-scope
481503
[`use`]: items/use-declarations.md
482504
[attributes]: attributes.md
505+
[const generic argument]: items.generics.const.argument
483506
[enumeration]: items/enumerations.md
484507
[expressions]: expressions.md
485508
[extern prelude]: names/preludes.md#extern-prelude
486509
[implementation]: items/implementations.md
510+
[inferred const]: items.generics.const.inferred
487511
[macro transcribers]: macros-by-example.md
488512
[macros]: macros.md
489513
[mbe]: macros-by-example.md

0 commit comments

Comments
 (0)