From 0ae56c208cdbc41eb2b71b9495d5c238fe806c6a Mon Sep 17 00:00:00 2001 From: Boxy Date: Mon, 9 Jun 2025 23:32:21 +0100 Subject: [PATCH 1/4] Document inferred const args --- src/items/generics.md | 21 +++++++++++++++++++++ src/paths.md | 1 + 2 files changed, 22 insertions(+) diff --git a/src/items/generics.md b/src/items/generics.md index 5558b66fd..1f7f5083b 100644 --- a/src/items/generics.md +++ b/src/items/generics.md @@ -227,6 +227,27 @@ fn generic() { } ``` +r[items.generics.const.inferred] + +r[items.generics.const.inferred.syntax] +```grammar,items +InferredConst -> + `_` + | `(` InferredConst `)` +``` + +r[items.generics.const.inferred.intro] +The inferred const asks the compiler to infer the const argument if possible based on the surrounding information available. + +```rust +fn make_buf() -> [u8; 1024] { + [0x1; _] +} +``` + +r[items.generics.const.inferred.constraint] +It cannot be used in item signatures. + r[items.generics.where] ## Where clauses diff --git a/src/paths.md b/src/paths.md index d4e929227..518667677 100644 --- a/src/paths.md +++ b/src/paths.md @@ -65,6 +65,7 @@ GenericArgsConst -> | LiteralExpression | `-` LiteralExpression | SimplePathSegment + | InferredConst GenericArgsBinding -> IDENTIFIER GenericArgs? `=` Type From ea9dc7aa06922a764b97f5fe5073484fcbb54201 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Fri, 13 Jun 2025 12:34:05 +0000 Subject: [PATCH 2/4] Revise a bit editorially --- src/items/generics.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/items/generics.md b/src/items/generics.md index 1f7f5083b..a2ccfce61 100644 --- a/src/items/generics.md +++ b/src/items/generics.md @@ -237,11 +237,12 @@ InferredConst -> ``` r[items.generics.const.inferred.intro] -The inferred const asks the compiler to infer the const argument if possible based on the surrounding information available. +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. ```rust fn make_buf() -> [u8; 1024] { [0x1; _] + // ^ Infers `1024`. } ``` From 74723e04cd564e9624c31552aa5d0c3003144103 Mon Sep 17 00:00:00 2001 From: Boxy Date: Fri, 13 Jun 2025 14:59:59 +0100 Subject: [PATCH 3/4] Dont add new grammar rules --- src/items/generics.md | 35 +++++++++++++---------------------- src/paths.md | 1 - 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/src/items/generics.md b/src/items/generics.md index a2ccfce61..d9ed9949e 100644 --- a/src/items/generics.md +++ b/src/items/generics.md @@ -171,6 +171,19 @@ fn example() { } ``` +r[items.generics.const.inferred] +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. + +```rust +fn make_buf() -> [u8; 1024] { + [0x1; _] + // ^ Infers `1024`. +} +``` + +r[items.generics.const.inferred.constraint] +It cannot be used in item signatures. + r[items.generics.const.type-ambiguity] When there is ambiguity if a generic argument could be resolved as either a type or const argument, it is always resolved as a type. Placing the argument @@ -227,28 +240,6 @@ fn generic() { } ``` -r[items.generics.const.inferred] - -r[items.generics.const.inferred.syntax] -```grammar,items -InferredConst -> - `_` - | `(` InferredConst `)` -``` - -r[items.generics.const.inferred.intro] -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. - -```rust -fn make_buf() -> [u8; 1024] { - [0x1; _] - // ^ Infers `1024`. -} -``` - -r[items.generics.const.inferred.constraint] -It cannot be used in item signatures. - r[items.generics.where] ## Where clauses diff --git a/src/paths.md b/src/paths.md index 518667677..d4e929227 100644 --- a/src/paths.md +++ b/src/paths.md @@ -65,7 +65,6 @@ GenericArgsConst -> | LiteralExpression | `-` LiteralExpression | SimplePathSegment - | InferredConst GenericArgsBinding -> IDENTIFIER GenericArgs? `=` Type From b09010dbbb8d7d041913d01a8312cef4a4576f5e Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 17 Jun 2025 22:18:02 +0000 Subject: [PATCH 4/4] 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. --- src/expressions/array-expr.md | 15 ++++++++- src/items/generics.md | 61 ++++++++++++++++++++++------------- src/paths.md | 28 ++++++++++++++-- 3 files changed, 78 insertions(+), 26 deletions(-) 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 d9ed9949e..c0ca74bf7 100644 --- a/src/items/generics.md +++ b/src/items/generics.md @@ -146,43 +146,56 @@ 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); -} - -const SOME_CONST: i32 = 12; - -fn example() { - // Example usage of a const argument. - double::<9>(); - double::<-123>(); - double::<{7 + 8}>(); - double::(); - double::<{ SOME_CONST + 5 }>(); -} +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]. + r[items.generics.const.inferred] -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. +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. ```rust -fn make_buf() -> [u8; 1024] { - [0x1; _] - // ^ Infers `1024`. +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] -It cannot be used in item signatures. +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] 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> { [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 @@ -314,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