Skip to content

Commit 002201d

Browse files
committed
Improve the generic_arg_infer docs
Syntactically, the inferred const is either an expression or an `InferredType`, depending on the context. Semantically, though, it's a new kind of const generic argument. Let's add the necessary language in various places to make this all as clear as possible.
1 parent 74723e0 commit 002201d

File tree

3 files changed

+72
-26
lines changed

3 files changed

+72
-26
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: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -146,43 +146,56 @@ 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-
}
161-
162-
const SOME_CONST: i32 = 12;
163-
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 }>();
171-
}
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.
172166
```
173167

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].
170+
174171
r[items.generics.const.inferred]
175-
Where a const argument is expected, an `_` (optionally surrounding by any number of matching parentheses), called the "inferred const", can be used instead. This asks the compiler to infer the const argument if possible based on surrounding information.
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.
176173

177174
```rust
178-
fn make_buf() -> [u8; 1024] {
179-
[0x1; _]
180-
// ^ Infers `1024`.
175+
fn make_buf<const N: usize>() -> [u8; N] {
176+
[0; _]
177+
// ^ Infers `N`.
181178
}
179+
let _: [u8; 1024] = make_buf::<_>();
180+
// ^ Infers `1024`.
182181
```
183182

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+
184192
r[items.generics.const.inferred.constraint]
185-
It cannot be used in item signatures.
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
198+
```
186199
187200
r[items.generics.const.type-ambiguity]
188201
When there is ambiguity if a generic argument could be resolved as either a
@@ -306,6 +319,7 @@ struct Foo<#[my_flexible_clone(unbounded)] H> {
306319
[block]: ../expressions/block-expr.md
307320
[const contexts]: ../const_eval.md#const-context
308321
[const expression]: ../const_eval.md#constant-expressions
322+
[const generic argument]: items.generics.const.argument
309323
[const item]: constant-items.md
310324
[enumerations]: enumerations.md
311325
[functions]: functions.md
@@ -314,6 +328,7 @@ struct Foo<#[my_flexible_clone(unbounded)] H> {
314328
[generic parameter scopes]: ../names/scopes.md#generic-parameter-scopes
315329
[higher-ranked lifetimes]: ../trait-bounds.md#higher-ranked-trait-bounds
316330
[implementations]: implementations.md
331+
[inferred const]: items.generics.const.inferred
317332
[item declarations]: ../statements.md#item-declarations
318333
[item]: ../items.md
319334
[literal]: ../expressions/literal-expr.md

src/paths.md

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,24 @@ 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.
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+
> [!NOTE]
111+
> 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].
96112
97113
r[paths.expr.impl-trait-params]
98114
The synthetic type parameters corresponding to `impl Trait` types are implicit,
@@ -480,10 +496,12 @@ mod without { // crate::without
480496
[`Self` scope]: names/scopes.md#self-scope
481497
[`use`]: items/use-declarations.md
482498
[attributes]: attributes.md
499+
[const generic argument]: items.generics.const.argument
483500
[enumeration]: items/enumerations.md
484501
[expressions]: expressions.md
485502
[extern prelude]: names/preludes.md#extern-prelude
486503
[implementation]: items/implementations.md
504+
[inferred const]: items.generics.const.inferred
487505
[macro transcribers]: macros-by-example.md
488506
[macros]: macros.md
489507
[mbe]: macros-by-example.md

0 commit comments

Comments
 (0)