Skip to content

Commit 6e74827

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 6e74827

File tree

3 files changed

+63
-26
lines changed

3 files changed

+63
-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: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -146,43 +146,47 @@ 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

184183
r[items.generics.const.inferred.constraint]
185-
It cannot be used in item signatures.
184+
The inferred const cannot be used in item signatures.
185+
186+
```rust,compile_fail
187+
fn f<const N: usize>(x: [u8; N]) -> [u8; _] { x }
188+
// ^ ERROR
189+
```
186190

187191
r[items.generics.const.type-ambiguity]
188192
When there is ambiguity if a generic argument could be resolved as either a
@@ -306,6 +310,7 @@ struct Foo<#[my_flexible_clone(unbounded)] H> {
306310
[block]: ../expressions/block-expr.md
307311
[const contexts]: ../const_eval.md#const-context
308312
[const expression]: ../const_eval.md#constant-expressions
313+
[const generic argument]: items.generics.const.argument
309314
[const item]: constant-items.md
310315
[enumerations]: enumerations.md
311316
[functions]: functions.md
@@ -314,6 +319,7 @@ struct Foo<#[my_flexible_clone(unbounded)] H> {
314319
[generic parameter scopes]: ../names/scopes.md#generic-parameter-scopes
315320
[higher-ranked lifetimes]: ../trait-bounds.md#higher-ranked-trait-bounds
316321
[implementations]: implementations.md
322+
[inferred const]: items.generics.const.inferred
317323
[item declarations]: ../statements.md#item-declarations
318324
[item]: ../items.md
319325
[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)