diff --git a/src/expressions/array-expr.md b/src/expressions/array-expr.md index 04374f3f3..883723467 100644 --- a/src/expressions/array-expr.md +++ b/src/expressions/array-expr.md @@ -35,7 +35,18 @@ r[expr.array.length-operand] The expression after the `;` is called the *length operand*. r[expr.array.length-restriction] -It must have type `usize` and be a [constant expression], such as a [literal] or a [constant item]. +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]). + +```rust +const C: usize = 1; +let _: [u8; C] = [0; 1]; // Literal. +let _: [u8; C] = [0; C]; // Constant item. +let _: [u8; C] = [0; _]; // Inferred const. +let _: [u8; C] = [0; (((_)))]; // Inferred const. +``` + +> [!NOTE] +> 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]. r[expr.array.repeat-behavior] 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 [IndexMut]: std::ops::IndexMut [Index]: std::ops::Index [array]: ../types/array.md +[const generic argument]: items.generics.const.argument [constant expression]: ../const_eval.md#constant-expressions [constant item]: ../items/constant-items.md +[inferred const]: items.generics.const.inferred [literal]: ../tokens.md#literals [memory location]: ../expressions.md#place-expressions-and-value-expressions [panic]: ../panic.md diff --git a/src/items/generics.md b/src/items/generics.md index 5558b66fd..c0ca74bf7 100644 --- a/src/items/generics.md +++ b/src/items/generics.md @@ -146,29 +146,55 @@ r[items.generics.const.argument] A const argument in a [path] specifies the const value to use for that item. r[items.generics.const.argument.const-expr] -The argument must 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). +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). > [!NOTE] > This syntactic restriction is necessary to avoid requiring infinite lookahead when parsing an expression inside of a type. ```rust -fn double() { - println!("doubled: {}", N * 2); -} +struct S; +const C: i64 = 1; +fn f() -> S { S } + +let _ = f::<1>(); // Literal. +let _ = f::<-1>(); // Negative literal. +let _ = f::<{ 1 + 2 }>(); // Constant expression. +let _ = f::(); // Single segment path. +let _ = f::<{ C + 1 }>(); // Constant expression. +let _: S<1> = f::<_>(); // Inferred const. +let _: S<1> = f::<(((_)))>(); // Inferred const. +``` + +> [!NOTE] +> 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]. -const SOME_CONST: i32 = 12; +r[items.generics.const.inferred] +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. -fn example() { - // Example usage of a const argument. - double::<9>(); - double::<-123>(); - double::<{7 + 8}>(); - double::(); - double::<{ SOME_CONST + 5 }>(); +```rust +fn make_buf() -> [u8; N] { + [0; _] + // ^ Infers `N`. } +let _: [u8; 1024] = make_buf::<_>(); +// ^ Infers `1024`. +``` + +> [!NOTE] +> An [inferred const] is not semantically an [expression][Expression] and so is not accepted within braces. +> +> ```rust,compile_fail +> fn f() -> [u8; N] { [0; _] } +> let _: [_; 1] = f::<{ _ }>(); +> // ^ ERROR `_` not allowed here +> ``` + +r[items.generics.const.inferred.constraint] +The inferred const cannot be used in item signatures. + +```rust,compile_fail +fn f(x: [u8; N]) -> [u8; _] { x } +// ^ ERROR not allowed ``` r[items.generics.const.type-ambiguity] @@ -293,6 +319,7 @@ struct Foo<#[my_flexible_clone(unbounded)] H> { [block]: ../expressions/block-expr.md [const contexts]: ../const_eval.md#const-context [const expression]: ../const_eval.md#constant-expressions +[const generic argument]: items.generics.const.argument [const item]: constant-items.md [enumerations]: enumerations.md [functions]: functions.md @@ -301,6 +328,7 @@ struct Foo<#[my_flexible_clone(unbounded)] H> { [generic parameter scopes]: ../names/scopes.md#generic-parameter-scopes [higher-ranked lifetimes]: ../trait-bounds.md#higher-ranked-trait-bounds [implementations]: implementations.md +[inferred const]: items.generics.const.inferred [item declarations]: ../statements.md#item-declarations [item]: ../items.md [literal]: ../expressions/literal-expr.md diff --git a/src/paths.md b/src/paths.md index d4e929227..9bf6e1ec6 100644 --- a/src/paths.md +++ b/src/paths.md @@ -91,8 +91,30 @@ The order of generic arguments is restricted to lifetime arguments, then type arguments, then const arguments, then equality constraints. r[paths.expr.complex-const-params] -Const arguments must be surrounded by braces unless they are a -[literal] or a single segment path. +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. + +```rust +mod m { + pub const C: usize = 1; +} +const C: usize = m::C; +fn f() -> [u8; N] { [0; N] } + +let _ = f::<1>(); // Literal. +let _: [_; 1] = f::<_>(); // Inferred const. +let _: [_; 1] = f::<(((_)))>(); // Inferred const. +let _ = f::(); // Single segment path. +let _ = f::<{ m::C }>(); // Multi-segment path must be braced. +``` + +```rust,compile_fail +fn f() -> [u8; N] { [0; _] } +let _: [_; 1] = f::<{ _ }>(); +// ^ ERROR `_` not allowed here +``` + +> [!NOTE] +> 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]. r[paths.expr.impl-trait-params] The synthetic type parameters corresponding to `impl Trait` types are implicit, @@ -480,10 +502,12 @@ mod without { // crate::without [`Self` scope]: names/scopes.md#self-scope [`use`]: items/use-declarations.md [attributes]: attributes.md +[const generic argument]: items.generics.const.argument [enumeration]: items/enumerations.md [expressions]: expressions.md [extern prelude]: names/preludes.md#extern-prelude [implementation]: items/implementations.md +[inferred const]: items.generics.const.inferred [macro transcribers]: macros-by-example.md [macros]: macros.md [mbe]: macros-by-example.md