From 2c4587ccf3eefa346dbf25c4dd82e2ab75c11027 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 30 Sep 2025 09:18:28 -0700 Subject: [PATCH 01/24] Move items/generics in preparation for generics restructuring Preparing to split into multiple subchapters. --- book.toml | 1 + src/SUMMARY.md | 2 +- src/{items/generics.md => types/generics/index.md} | 0 3 files changed, 2 insertions(+), 1 deletion(-) rename src/{items/generics.md => types/generics/index.md} (100%) diff --git a/book.toml b/book.toml index 98697bf6c2..ee489523be 100644 --- a/book.toml +++ b/book.toml @@ -50,6 +50,7 @@ use-boolean-and = true "/expressions/operator-expr.html#the-question-mark-operator" = "operator-expr.html#the-try-propagation-expression" "/glossary.html#object-safe-traits" = "glossary.html#dyn-compatible-traits" "/items/extern-crates.html#extern-prelude" = "../names/preludes.html#extern-prelude" +"/items/generics.html" = "../types/generics/index.html" "/items/modules.html#prelude-items" = "../names/preludes.html" "/items/traits.html#object-safety" = "traits.html#dyn-compatibility" "/lifetime-elision.html#static-lifetime-elision" = "lifetime-elision.html#const-and-static-elision" diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 0692b3f433..9493755c35 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -35,7 +35,6 @@ - [Traits](items/traits.md) - [Implementations](items/implementations.md) - [External blocks](items/external-blocks.md) - - [Generic parameters](items/generics.md) - [Associated items](items/associated-items.md) - [Attributes](attributes.md) @@ -93,6 +92,7 @@ - [Impl trait type](types/impl-trait.md) - [Type parameters](types/parameters.md) - [Inferred type](types/inferred.md) + - [Generics](types/generics/index.md) - [Dynamically sized types](dynamically-sized-types.md) - [Type layout](type-layout.md) - [Interior mutability](interior-mutability.md) diff --git a/src/items/generics.md b/src/types/generics/index.md similarity index 100% rename from src/items/generics.md rename to src/types/generics/index.md From 9ccddc1a5225e181bb6dba5ac378bc27dc774fe9 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 30 Sep 2025 11:51:47 -0700 Subject: [PATCH 02/24] Update generic rule names after move --- src/types/generics/index.md | 52 ++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/types/generics/index.md b/src/types/generics/index.md index 6161d11975..2fdea81173 100644 --- a/src/types/generics/index.md +++ b/src/types/generics/index.md @@ -1,7 +1,7 @@ -r[items.generics] +r[generics] # Generic parameters -r[items.generics.syntax] +r[generics.syntax] ```grammar,items GenericParams -> `<` ( GenericParam (`,` GenericParam)* `,`? )? `>` @@ -16,13 +16,13 @@ ConstParam -> ( `=` ( BlockExpression | IDENTIFIER | `-`?LiteralExpression ) )? ``` -r[items.generics.syntax.intro] +r[generics.syntax.intro] [Functions], [type aliases], [structs], [enumerations], [unions], [traits], and [implementations] may be *parameterized* by types, constants, and lifetimes. These parameters are listed in angle brackets (`<...>`), usually immediately after the name of the item and before its definition. For implementations, which don't have a name, they come directly after `impl`. -r[items.generics.syntax.decl-order] +r[generics.syntax.decl-order] The order of generic parameters is restricted to lifetime parameters and then type and const parameters intermixed. -r[items.generics.syntax.duplicate-params] +r[generics.syntax.duplicate-params] The same parameter name may not be declared more than once in a [GenericParams] list. Some examples of items with type, const, and lifetime parameters: @@ -35,28 +35,28 @@ struct InnerArray([T; N]); struct EitherOrderWorks(U); ``` -r[items.generics.syntax.scope] +r[generics.syntax.scope] Generic parameters are in scope within the item definition where they are declared. They are not in scope for items declared within the body of a function as described in [item declarations]. See [generic parameter scopes] for more details. -r[items.generics.builtin-generic-types] +r[generics.builtin-generic-types] [References], [raw pointers], [arrays], [slices], [tuples], and [function pointers] have lifetime or type parameters as well, but are not referred to with path syntax. -r[items.generics.invalid-lifetimes] +r[generics.invalid-lifetimes] `'_` and `'static` are not valid lifetime parameter names. -r[items.generics.const] +r[generics.const] ### Const generics -r[items.generics.const.intro] +r[generics.const.intro] *Const generic parameters* allow items to be generic over constant values. -r[items.generics.const.namespace] +r[generics.const.namespace] The const identifier introduces a name in the [value namespace] for the constant parameter, and all instances of the item must be instantiated with a value of the given type. -r[items.generics.const.allowed-types] +r[generics.const.allowed-types] The only allowed types of const parameters are `u8`, `u16`, `u32`, `u64`, `u128`, `usize`, `i8`, `i16`, `i32`, `i64`, `i128`, `isize`, `char` and `bool`. -r[items.generics.const.use] +r[generics.const.use] Const parameters can be used anywhere a [const item] can be used, with the exception that when used in a [type] or [array repeat expression], it must be standalone (as described below). That is, they are allowed in the following places: 1. As an applied const to any type which forms a part of the signature of the item in question. @@ -108,7 +108,7 @@ fn foo() { } ``` -r[items.generics.const.standalone] +r[generics.const.standalone] As a further restriction, const parameters may only appear as a standalone argument inside of a [type] or [array repeat expression]. In those contexts, they may only be used as a single segment [path expression], possibly inside a [block] (such as `N` or `{N}`). That is, they cannot be combined with other expressions. ```rust,compile_fail @@ -122,10 +122,10 @@ fn bad_function() -> [u8; {N + 1}] { } ``` -r[items.generics.const.argument] +r[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] +r[generics.const.argument.const-expr] 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] @@ -148,7 +148,7 @@ 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] +r[generics.const.inferred] Where a const argument is expected, an `_` (optionally surrounded 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 @@ -169,7 +169,7 @@ let _: [u8; 1024] = make_buf::<_>(); > // ^ ERROR `_` not allowed here > ``` -r[items.generics.const.inferred.constraint] +r[generics.const.inferred.constraint] The inferred const cannot be used in item signatures. ```rust,compile_fail @@ -177,7 +177,7 @@ fn f(x: [u8; N]) -> [u8; _] { x } // ^ ERROR not allowed ``` -r[items.generics.const.type-ambiguity] +r[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 in a block expression can force it to be interpreted as a const argument. @@ -192,7 +192,7 @@ fn foo() -> Foo { todo!() } // ERROR fn bar() -> Foo<{ N }> { todo!() } // ok ``` -r[items.generics.const.variance] +r[generics.const.variance] Unlike type and lifetime parameters, const parameters can be declared without being used inside of a parameterized item, with the exception of implementations as described in [generic implementations]: ```rust,compile_fail @@ -207,7 +207,7 @@ struct Unconstrained; impl Unconstrained {} ``` -r[items.generics.const.exhaustiveness] +r[generics.const.exhaustiveness] When resolving a trait bound obligation, the exhaustiveness of all implementations of const parameters is not considered when determining if the bound is satisfied. For example, in the following, even though all possible const values for the `bool` type are implemented, it is still an error that the trait bound is not satisfied: ```rust,compile_fail @@ -223,10 +223,10 @@ fn generic() { } ``` -r[items.generics.where] +r[generics.where] ## Where clauses -r[items.generics.where.syntax] +r[generics.where.syntax] ```grammar,items WhereClause -> `where` ( WhereClauseItem `,` )* WhereClauseItem? @@ -239,10 +239,10 @@ LifetimeWhereClauseItem -> Lifetime `:` LifetimeBounds TypeBoundWhereClauseItem -> ForLifetimes? Type `:` Bounds? ``` -r[items.generics.where.intro] +r[generics.where.intro] *Where clauses* provide another way to specify bounds on type and lifetime parameters as well as a way to specify bounds on types that aren't type parameters. -r[items.generics.where.higher-ranked-lifetimes] +r[generics.where.higher-ranked-lifetimes] The `for` keyword can be used to introduce [higher-ranked lifetimes]. It only allows [LifetimeParam] parameters. ```rust @@ -257,7 +257,7 @@ where } ``` -r[items.generics.attributes] +r[generics.attributes] ## Attributes Generic lifetime and type parameters allow [attributes] on them. There are no built-in attributes that do anything in this position, although custom derive attributes may give meaning to it. From 330aff947f773aff701fecf5655bf4907662907f Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 30 Sep 2025 11:52:01 -0700 Subject: [PATCH 03/24] Update links to generics chapter after move --- src/attributes.md | 1 - src/const_eval.md | 6 ++-- src/crates-and-source-files.md | 2 +- src/expressions/array-expr.md | 4 +-- src/glossary.md | 2 +- src/items/associated-items.md | 4 +-- src/items/implementations.md | 2 +- src/items/traits.md | 3 +- src/items/use-declarations.md | 2 +- src/keywords.md | 2 +- src/names.md | 2 +- src/names/namespaces.md | 6 ++-- src/names/scopes.md | 4 +-- src/paths.md | 4 +-- src/syntax-index.md | 12 +++---- src/trait-bounds.md | 4 +-- src/types/generics/index.md | 66 +++++++++++++++++----------------- 17 files changed, 61 insertions(+), 65 deletions(-) diff --git a/src/attributes.md b/src/attributes.md index dd7cec5a8a..cfd7707009 100644 --- a/src/attributes.md +++ b/src/attributes.md @@ -351,7 +351,6 @@ The following is an index of all built-in attributes. [expression statement]: statements.md#expression-statements [external blocks]: items/external-blocks.md [functions]: items/functions.md -[generics]: items/generics.md [implementations]: items/implementations.md [item declarations]: items.md [match expressions]: expressions/match-expr.md diff --git a/src/const_eval.md b/src/const_eval.md index c06b343b04..f388898123 100644 --- a/src/const_eval.md +++ b/src/const_eval.md @@ -303,11 +303,11 @@ The types of a const function's parameters and return type are restricted to tho [comparison]: expressions/operator-expr.md#comparison-operators [const block]: expressions/block-expr.md#const-blocks [const functions]: items/functions.md#const-functions -[const generic argument]: items/generics.md#const-generics -[const generic parameters]: items/generics.md#const-generics +[const generic argument]: generics.const +[const generic parameters]: generics.const [constant expressions]: #constant-expressions [constants]: items/constant-items.md -[Const parameters]: items/generics.md +[Const parameters]: generics.const [dereference expression]: expr.deref [dereference expressions]: expr.deref [destructors]: destructors.md diff --git a/src/crates-and-source-files.md b/src/crates-and-source-files.md index 68dfa61bef..12902661cb 100644 --- a/src/crates-and-source-files.md +++ b/src/crates-and-source-files.md @@ -139,4 +139,4 @@ The crate name must not be empty, and must only contain [Unicode alphanumeric] o [panic-docs]: panic.md#unwinding-across-ffi-boundaries [shebang]: shebang.md [trait or lifetime bounds]: trait-bounds.md -[where clauses]: items/generics.md#where-clauses +[where clauses]: generics.where diff --git a/src/expressions/array-expr.md b/src/expressions/array-expr.md index d0fe247635..4a82a47614 100644 --- a/src/expressions/array-expr.md +++ b/src/expressions/array-expr.md @@ -132,11 +132,11 @@ 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 +[const generic argument]: generics.const.argument [const block expression]: expr.block.const [constant expression]: ../const_eval.md#constant-expressions [constant item]: ../items/constant-items.md -[inferred const]: items.generics.const.inferred +[inferred const]: generics.const.inferred [literal]: ../tokens.md#literals [memory location]: ../expressions.md#place-expressions-and-value-expressions [panic]: ../panic.md diff --git a/src/glossary.md b/src/glossary.md index 6a7afcfaae..d06e548c31 100644 --- a/src/glossary.md +++ b/src/glossary.md @@ -279,7 +279,7 @@ assert_eq!(0, size_of::()); [fields]: expressions/field-expr.md [free item]: #free-item [function items]: type.fn-item -[generic parameters]: items/generics.md +[generic parameters]: generics [identifier]: identifiers.md [identifiers]: identifiers.md [implementation]: items/implementations.md diff --git a/src/items/associated-items.md b/src/items/associated-items.md index 0c8d0c5906..11f5733244 100644 --- a/src/items/associated-items.md +++ b/src/items/associated-items.md @@ -509,6 +509,6 @@ fn main() { [method call operator]: ../expressions/method-call-expr.md [path]: ../paths.md [regular function parameters]: functions.md#attributes-on-function-parameters -[generic parameters]: generics.md -[where clauses]: generics.md#where-clauses +[generic parameters]: generics +[where clauses]: generics.where [constant evaluation]: ../const_eval.md diff --git a/src/items/implementations.md b/src/items/implementations.md index 12764a433a..6a2940a548 100644 --- a/src/items/implementations.md +++ b/src/items/implementations.md @@ -280,7 +280,7 @@ Implementations may contain outer [attributes] before the `impl` keyword and inn [`cfg`]: ../conditional-compilation.md [`deprecated`]: ../attributes/diagnostics.md#the-deprecated-attribute [`doc`]: ../../rustdoc/the-doc-attribute.html -[generic parameters]: generics.md +[generic parameters]: generics [methods]: associated-items.md#methods [path]: ../paths.md [the lint check attributes]: ../attributes/diagnostics.md#lint-check-attributes diff --git a/src/items/traits.md b/src/items/traits.md index fe1a985f53..947f039e32 100644 --- a/src/items/traits.md +++ b/src/items/traits.md @@ -373,8 +373,7 @@ fn main() { [method]: associated-items.md#methods [supertraits]: #supertraits [implementations]: implementations.md -[generics]: generics.md -[where clauses]: generics.md#where-clauses +[where clauses]: generics.where [generic functions]: functions.md#generic-functions [unsafe]: ../unsafety.md [trait implementation]: implementations.md#trait-implementations diff --git a/src/items/use-declarations.md b/src/items/use-declarations.md index 49781895c8..4d3811ef49 100644 --- a/src/items/use-declarations.md +++ b/src/items/use-declarations.md @@ -478,7 +478,7 @@ r[items.use.restrictions.variant] [`self`]: ../paths.md#self [associated items]: associated-items.md [extern prelude]: ../names/preludes.md#extern-prelude -[generic parameters]: generics.md +[generic parameters]: generics [items]: ../items.md [local variables]: ../variables.md [module]: items.mod diff --git a/src/keywords.md b/src/keywords.md index 3c143d441d..92aa869ffd 100644 --- a/src/keywords.md +++ b/src/keywords.md @@ -153,6 +153,6 @@ r[lex.keywords.weak.dyn.edition2018] [variants]: items/enumerations.md [`dyn`]: types/trait-object.md [loop label]: expressions/loop-expr.md#loop-labels -[generic lifetime parameter]: items/generics.md +[generic lifetime parameter]: generics [external blocks]: items/external-blocks.md [raw borrow operators]: expressions/operator-expr.md#raw-borrow-operators diff --git a/src/names.md b/src/names.md index 412f9ed6cd..48ed7b2b56 100644 --- a/src/names.md +++ b/src/names.md @@ -139,7 +139,7 @@ Additionally, the crate root module does not have a name, but can be referred to [floating-point types]: types/numeric.md#floating-point-types [Function declarations]: items/functions.md [function parameters]: items/functions.md#function-parameters -[Generic parameters]: items/generics.md +[Generic parameters]: generics [Higher ranked trait bounds]: trait-bounds.md#higher-ranked-trait-bounds [Implementation]: items/implementations.md [Integer types]: types/numeric.md#integer-types diff --git a/src/names/namespaces.md b/src/names/namespaces.md index 58a96c7faf..f7ea09ebcd 100644 --- a/src/names/namespaces.md +++ b/src/names/namespaces.md @@ -149,9 +149,9 @@ For example, the [`cfg` attribute] and the [`cfg` macro] are two different entit [Function declarations]: ../items/functions.md [function parameters]: ../items/functions.md#function-parameters [Function-like procedural macros]: ../procedural-macros.md#the-proc_macro-attribute -[Generic const parameters]: ../items/generics.md#const-generics -[Generic lifetime parameters]: ../items/generics.md -[Generic type parameters]: ../items/generics.md +[Generic const parameters]: generics.const +[Generic lifetime parameters]: generics +[Generic type parameters]: generics [Loop labels]: ../expressions/loop-expr.md#loop-labels [Module declarations]: ../items/modules.md [name resolution]: name-resolution.md diff --git a/src/names/scopes.md b/src/names/scopes.md index 44c3dbf788..a4df42f2e3 100644 --- a/src/names/scopes.md +++ b/src/names/scopes.md @@ -342,9 +342,9 @@ impl ImplExample { [call expressions]: ../expressions/call-expr.md [Closure parameter]: ../expressions/closure-expr.md [closures]: ../expressions/closure-expr.md -[const arguments]: ../items/generics.md#const-generics +[const arguments]: generics.const [const contexts]: ../const_eval.md#const-context -[Const generic parameters]: ../items/generics.md#const-generics +[Const generic parameters]: generics.const [Const items]: ../items/constant-items.md [Constant]: ../items/constant-items.md [Derive macro helper attributes]: ../procedural-macros.md#derive-macro-helper-attributes diff --git a/src/paths.md b/src/paths.md index cb36f3af20..ceb95f7dba 100644 --- a/src/paths.md +++ b/src/paths.md @@ -496,12 +496,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 +[const generic argument]: 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 +[inferred const]: generics.const.inferred [macro transcribers]: macros-by-example.md [macros]: macros.md [mbe]: macros-by-example.md diff --git a/src/syntax-index.md b/src/syntax-index.md index bb3d65c97e..f0107be7f9 100644 --- a/src/syntax-index.md +++ b/src/syntax-index.md @@ -306,7 +306,7 @@ This appendix provides an index of tokens and common forms with links to where t [const assembly operands]: asm.operand-type.supported-operands.const [const blocks]: expr.block.const [const functions]: const-eval.const-fn -[const generics]: items.generics.const +[const generics]: generics.const [const items]: items.const [constant items]: items.const [continue expressions]: expr.loop.continue @@ -328,9 +328,9 @@ This appendix provides an index of tokens and common forms with links to where t [function pointer type]: type.fn-pointer [function pointer types]: type.fn-pointer [functions]: items.fn -[generic arguments]: items.generics -[generic definitions]: items.generics -[generics]: items.generics +[generic arguments]: generics +[generic definitions]: generics +[generics]: generics [glob imports]: items.use.glob [grouped patterns]: patterns.paren [higher-ranked trait bounds]: bound.higher-ranked @@ -340,7 +340,7 @@ This appendix provides an index of tokens and common forms with links to where t [if let]: expr.if.let [impl trait types]: type.impl-trait.return [implementations]: items.impl -[inferred const]: items.generics.const.inferred +[inferred const]: generics.const.inferred [inferred type]: type.inferred [infinite loop expressions]: expr.loop.infinite [infinite loops]: expr.loop.infinite @@ -451,6 +451,6 @@ This appendix provides an index of tokens and common forms with links to where t [use items]: items.use [variadic functions]: items.extern.variadic [visibility]: vis -[where clauses]: items.generics.where +[where clauses]: generics.where [while let]: expr.loop.while.let [wildcard pattern]: patterns.wildcard diff --git a/src/trait-bounds.md b/src/trait-bounds.md index 6a5b870c29..9fcd058353 100644 --- a/src/trait-bounds.md +++ b/src/trait-bounds.md @@ -243,7 +243,7 @@ Certain bounds lists may include a `use<..>` bound to control which generic para [associated types]: items/associated-items.md#associated-types [hrtb-scopes]: names/scopes.md#higher-ranked-trait-bound-scopes [supertraits]: items/traits.md#supertraits -[generic]: items/generics.md +[generic]: generics [higher-ranked lifetimes]: #higher-ranked-trait-bounds [precise capturing]: types/impl-trait.md#precise-capturing [slice]: types/slice.md @@ -251,4 +251,4 @@ Certain bounds lists may include a `use<..>` bound to control which generic para [trait object]: types/trait-object.md [trait objects]: types/trait-object.md [type parameters]: types/parameters.md -[where clause]: items/generics.md#where-clauses +[where clause]: generics.where diff --git a/src/types/generics/index.md b/src/types/generics/index.md index 2fdea81173..84dda456c3 100644 --- a/src/types/generics/index.md +++ b/src/types/generics/index.md @@ -274,37 +274,35 @@ struct Foo<#[my_flexible_clone(unbounded)] H> { } ``` -[array repeat expression]: ../expressions/array-expr.md -[arrays]: ../types/array.md -[slices]: ../types/slice.md -[associated const]: associated-items.md#associated-constants -[associated type]: associated-items.md#associated-types -[attributes]: ../attributes.md -[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 -[function pointers]: ../types/function-pointer.md -[generic implementations]: implementations.md#generic-implementations -[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 -[path]: ../paths.md -[path expression]: ../expressions/path-expr.md -[raw pointers]: ../types/pointer.md#raw-pointers-const-and-mut -[references]: ../types/pointer.md#shared-references- -[structs]: structs.md -[tuples]: ../types/tuple.md -[trait object]: ../types/trait-object.md -[traits]: traits.md -[type aliases]: type-aliases.md -[type]: ../types.md -[unions]: unions.md -[value namespace]: ../names/namespaces.md +[array repeat expression]: expr.array +[arrays]: type.array +[associated const]: items.associated.const +[associated type]: items.associated.type +[block]: expr.block +[const contexts]: const-eval.const-context +[const expression]: const-eval.const-expr +[const generic argument]: generics.const.argument +[const item]: items.const +[enumerations]: items.enum +[function pointers]: type.fn-pointer +[functions]: items.fn +[generic implementations]: items.impl.generics +[generic parameter scopes]: names.scopes.generic-parameters +[higher-ranked lifetimes]: bound.higher-ranked +[implementations]: items.impl +[inferred const]: generics.const.inferred +[item declarations]: statement.item +[item]: items +[literal]: expr.literal +[path expression]: expr.path +[path]: paths +[raw pointers]: type.pointer.raw +[references]: type.pointer.reference +[slices]: type.slice +[structs]: items.struct +[trait object]: type.trait-object +[traits]: items.traits +[tuples]: type.tuple +[type aliases]: items.type +[unions]: items.union +[value namespace]: names.namespaces From 0fc2fd1409abb0204ba7b3d69fa18eabe6847c23 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 7 Oct 2025 14:15:22 -0700 Subject: [PATCH 04/24] Update generic parameters to fit into the chapter This makes some small editorial and rule name updates to prepare the Generics chapter for having separate sections on parameters, arguments, and the different generic kinds. --- src/types/generics/index.md | 48 +++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/src/types/generics/index.md b/src/types/generics/index.md index 84dda456c3..a8d8715e8c 100644 --- a/src/types/generics/index.md +++ b/src/types/generics/index.md @@ -1,7 +1,22 @@ r[generics] -# Generic parameters +# Generics -r[generics.syntax] +r[generics.parameters] +## Generic parameters + +r[generics.parameters.intro] +[Functions], [type aliases], [structs], [enumerations], [unions], [traits], and [implementations] may be *parameterized* by types, constants, and lifetimes. These parameters are listed in angle brackets (`<...>`), usually immediately after the name of the item and before its definition. For implementations, which don't have a name, they come directly after `impl`. + +> [!EXAMPLE] +> ```rust +> fn foo<'a, T>() {} +> trait A {} +> struct Ref<'a, T> where T: 'a { r: &'a T } +> struct InnerArray([T; N]); +> struct EitherOrderWorks(U); +> ``` + +r[generics.parameters.syntax] ```grammar,items GenericParams -> `<` ( GenericParam (`,` GenericParam)* `,`? )? `>` @@ -16,36 +31,23 @@ ConstParam -> ( `=` ( BlockExpression | IDENTIFIER | `-`?LiteralExpression ) )? ``` -r[generics.syntax.intro] -[Functions], [type aliases], [structs], [enumerations], [unions], [traits], and [implementations] may be *parameterized* by types, constants, and lifetimes. These parameters are listed in angle brackets (`<...>`), usually immediately after the name of the item and before its definition. For implementations, which don't have a name, they come directly after `impl`. - -r[generics.syntax.decl-order] +r[generics.parameters.decl-order] The order of generic parameters is restricted to lifetime parameters and then type and const parameters intermixed. -r[generics.syntax.duplicate-params] +r[generics.parameters.duplicate-params] The same parameter name may not be declared more than once in a [GenericParams] list. -Some examples of items with type, const, and lifetime parameters: - -```rust -fn foo<'a, T>() {} -trait A {} -struct Ref<'a, T> where T: 'a { r: &'a T } -struct InnerArray([T; N]); -struct EitherOrderWorks(U); -``` - -r[generics.syntax.scope] +r[generics.parameters.scope] Generic parameters are in scope within the item definition where they are declared. They are not in scope for items declared within the body of a function as described in [item declarations]. See [generic parameter scopes] for more details. -r[generics.builtin-generic-types] +r[generics.parameters.builtin-generic-types] [References], [raw pointers], [arrays], [slices], [tuples], and [function pointers] have lifetime or type parameters as well, but are not referred to with path syntax. -r[generics.invalid-lifetimes] +r[generics.parameters.invalid-lifetimes] `'_` and `'static` are not valid lifetime parameter names. r[generics.const] -### Const generics +## Const generics r[generics.const.intro] *Const generic parameters* allow items to be generic over constant values. @@ -169,7 +171,7 @@ let _: [u8; 1024] = make_buf::<_>(); > // ^ ERROR `_` not allowed here > ``` -r[generics.const.inferred.constraint] +r[generics.parameters.const.inferred.constraint] The inferred const cannot be used in item signatures. ```rust,compile_fail @@ -257,7 +259,7 @@ where } ``` -r[generics.attributes] +r[generics.parameters.attributes] ## Attributes Generic lifetime and type parameters allow [attributes] on them. There are no built-in attributes that do anything in this position, although custom derive attributes may give meaning to it. From 36851dba831cac3a5965633bbd865b7947f529d0 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 3 Feb 2026 13:47:03 -0800 Subject: [PATCH 05/24] Move where clause to the bounds chapter Organizationally I think it makes more sense, since this chapter is all about defining bounds. --- book.toml | 1 + src/crates-and-source-files.md | 2 +- src/items/associated-items.md | 2 +- src/items/traits.md | 2 +- src/syntax-index.md | 2 +- src/trait-bounds.md | 36 +++++++++++++++++++++++++++++++++- src/types/generics/index.md | 34 -------------------------------- 7 files changed, 40 insertions(+), 39 deletions(-) diff --git a/book.toml b/book.toml index ee489523be..42e9451b78 100644 --- a/book.toml +++ b/book.toml @@ -51,6 +51,7 @@ use-boolean-and = true "/glossary.html#object-safe-traits" = "glossary.html#dyn-compatible-traits" "/items/extern-crates.html#extern-prelude" = "../names/preludes.html#extern-prelude" "/items/generics.html" = "../types/generics/index.html" +"/items/generics.html#where-clauses" = "../trait-bounds.html#where-clauses" "/items/modules.html#prelude-items" = "../names/preludes.html" "/items/traits.html#object-safety" = "traits.html#dyn-compatibility" "/lifetime-elision.html#static-lifetime-elision" = "lifetime-elision.html#const-and-static-elision" diff --git a/src/crates-and-source-files.md b/src/crates-and-source-files.md index 12902661cb..e97431c45a 100644 --- a/src/crates-and-source-files.md +++ b/src/crates-and-source-files.md @@ -139,4 +139,4 @@ The crate name must not be empty, and must only contain [Unicode alphanumeric] o [panic-docs]: panic.md#unwinding-across-ffi-boundaries [shebang]: shebang.md [trait or lifetime bounds]: trait-bounds.md -[where clauses]: generics.where +[where clauses]: bound.where diff --git a/src/items/associated-items.md b/src/items/associated-items.md index 11f5733244..5a567db081 100644 --- a/src/items/associated-items.md +++ b/src/items/associated-items.md @@ -510,5 +510,5 @@ fn main() { [path]: ../paths.md [regular function parameters]: functions.md#attributes-on-function-parameters [generic parameters]: generics -[where clauses]: generics.where +[where clauses]: bound.where [constant evaluation]: ../const_eval.md diff --git a/src/items/traits.md b/src/items/traits.md index 947f039e32..1375e8bb27 100644 --- a/src/items/traits.md +++ b/src/items/traits.md @@ -373,7 +373,7 @@ fn main() { [method]: associated-items.md#methods [supertraits]: #supertraits [implementations]: implementations.md -[where clauses]: generics.where +[where clauses]: bound.where [generic functions]: functions.md#generic-functions [unsafe]: ../unsafety.md [trait implementation]: implementations.md#trait-implementations diff --git a/src/syntax-index.md b/src/syntax-index.md index f0107be7f9..f8edda6cf4 100644 --- a/src/syntax-index.md +++ b/src/syntax-index.md @@ -451,6 +451,6 @@ This appendix provides an index of tokens and common forms with links to where t [use items]: items.use [variadic functions]: items.extern.variadic [visibility]: vis -[where clauses]: generics.where +[where clauses]: bound.where [while let]: expr.loop.while.let [wildcard pattern]: patterns.wildcard diff --git a/src/trait-bounds.md b/src/trait-bounds.md index 9fcd058353..457fa14f34 100644 --- a/src/trait-bounds.md +++ b/src/trait-bounds.md @@ -95,6 +95,40 @@ struct UsesA<'a, T>(A<'a, T>); r[bound.trait-object] Trait and lifetime bounds are also used to name [trait objects]. +r[bound.where] +## Where clauses + +r[bound.where.intro] +*Where clauses* provide another way to specify bounds on type and lifetime parameters as well as a way to specify bounds on types that aren't type parameters. + +r[bound.where.syntax] +```grammar,items +WhereClause -> `where` ( WhereClauseItem `,` )* WhereClauseItem? + +WhereClauseItem -> + LifetimeWhereClauseItem + | TypeBoundWhereClauseItem + +LifetimeWhereClauseItem -> Lifetime `:` LifetimeBounds + +TypeBoundWhereClauseItem -> ForLifetimes? Type `:` Bounds? +``` + +r[bound.where.higher-ranked-lifetimes] +The `for` keyword can be used to introduce [higher-ranked lifetimes]. It only allows [LifetimeParam] parameters. + +```rust +struct A +where + T: Iterator, // Could use A instead + T::Item: Copy, // Bound on an associated type + String: PartialEq, // Bound on `String`, using the type parameter + i32: Default, // Allowed, but not useful +{ + f: T, +} +``` + r[bound.sized] ## `?Sized` @@ -251,4 +285,4 @@ Certain bounds lists may include a `use<..>` bound to control which generic para [trait object]: types/trait-object.md [trait objects]: types/trait-object.md [type parameters]: types/parameters.md -[where clause]: generics.where +[where clause]: bound.where diff --git a/src/types/generics/index.md b/src/types/generics/index.md index a8d8715e8c..35fdf7dc9b 100644 --- a/src/types/generics/index.md +++ b/src/types/generics/index.md @@ -225,40 +225,6 @@ fn generic() { } ``` -r[generics.where] -## Where clauses - -r[generics.where.syntax] -```grammar,items -WhereClause -> `where` ( WhereClauseItem `,` )* WhereClauseItem? - -WhereClauseItem -> - LifetimeWhereClauseItem - | TypeBoundWhereClauseItem - -LifetimeWhereClauseItem -> Lifetime `:` LifetimeBounds - -TypeBoundWhereClauseItem -> ForLifetimes? Type `:` Bounds? -``` - -r[generics.where.intro] -*Where clauses* provide another way to specify bounds on type and lifetime parameters as well as a way to specify bounds on types that aren't type parameters. - -r[generics.where.higher-ranked-lifetimes] -The `for` keyword can be used to introduce [higher-ranked lifetimes]. It only allows [LifetimeParam] parameters. - -```rust -struct A -where - T: Iterator, // Could use A instead - T::Item: Copy, // Bound on an associated type - String: PartialEq, // Bound on `String`, using the type parameter - i32: Default, // Allowed, but not useful -{ - f: T, -} -``` - r[generics.parameters.attributes] ## Attributes From 581a13a2f6cf80476bf27a131c1539830f24c716 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 3 Feb 2026 13:47:12 -0800 Subject: [PATCH 06/24] Move intro to the top This follows the intended style that intros come first in a section. --- src/trait-bounds.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/trait-bounds.md b/src/trait-bounds.md index 457fa14f34..cf6ee8232e 100644 --- a/src/trait-bounds.md +++ b/src/trait-bounds.md @@ -1,6 +1,13 @@ r[bound] # Trait and lifetime bounds +r[bound.intro] +[Trait] and lifetime bounds provide a way for [generic items][generic] to restrict which types and lifetimes are used as their parameters. Bounds can be provided on any type in a [where clause]. There are also shorter forms for certain common cases: + +* Bounds written after declaring a [generic parameter][generic]: `fn f() {}` is the same as `fn f() where A: Copy {}`. +* In trait declarations as [supertraits]: `trait Circle : Shape {}` is equivalent to `trait Circle where Self : Shape {}`. +* In trait declarations as bounds on [associated types]: `trait A { type B: Copy; }` is equivalent to `trait A where Self::B: Copy { type B; }`. + r[bound.syntax] ```grammar,miscellaneous Bounds -> Bound ( `+` Bound )* `+`? @@ -30,13 +37,6 @@ UseBoundGenericArg -> | `Self` ``` -r[bound.intro] -[Trait] and lifetime bounds provide a way for [generic items][generic] to restrict which types and lifetimes are used as their parameters. Bounds can be provided on any type in a [where clause]. There are also shorter forms for certain common cases: - -* Bounds written after declaring a [generic parameter][generic]: `fn f() {}` is the same as `fn f() where A: Copy {}`. -* In trait declarations as [supertraits]: `trait Circle : Shape {}` is equivalent to `trait Circle where Self : Shape {}`. -* In trait declarations as bounds on [associated types]: `trait A { type B: Copy; }` is equivalent to `trait A where Self::B: Copy { type B; }`. - r[bound.satisfaction] Bounds on an item must be satisfied when using the item. When type checking and borrow checking a generic item, the bounds can be used to determine that a trait is implemented for a type. For example, given `Ty: Trait` From 3e5388469eb83d5d723e5f008d3e9fbb090423da Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 10 Feb 2026 14:26:36 -0800 Subject: [PATCH 07/24] Move generic args to the generics chapter This moves the generic args so that the Generics chapter is whole, and covers all the aspects of generics. --- src/paths.md | 54 ------------------------- src/types/generics/index.md | 79 ++++++++++++++++++++++++++++++++++++- 2 files changed, 78 insertions(+), 55 deletions(-) diff --git a/src/paths.md b/src/paths.md index ceb95f7dba..7a3663e01a 100644 --- a/src/paths.md +++ b/src/paths.md @@ -50,25 +50,6 @@ PathExprSegment -> PathIdentSegment -> IDENTIFIER | `super` | `self` | `Self` | `crate` | `$crate` - -GenericArgs -> - `<` `>` - | `<` ( GenericArg `,` )* GenericArg `,`? `>` - -GenericArg -> - Lifetime | Type | GenericArgsConst | GenericArgsBinding | GenericArgsBounds - -GenericArgsConst -> - BlockExpression - | LiteralExpression - | `-` LiteralExpression - | SimplePathSegment - -GenericArgsBinding -> - IDENTIFIER GenericArgs? `=` Type - -GenericArgsBounds -> - IDENTIFIER GenericArgs? `:` Bounds ``` r[paths.expr.intro] @@ -82,38 +63,6 @@ The `::` token is required before the opening `<` for generic arguments to avoid Vec::::with_capacity(1024); ``` -r[paths.expr.argument-order] -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], 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, and these cannot be explicitly specified. - r[paths.qualified] ## Qualified paths @@ -491,17 +440,14 @@ mod without { // crate::without [`$crate`]: macro.decl.hygiene.crate [implementations]: items/implementations.md [items]: items.md -[literal]: expressions/literal-expr.md [use declarations]: items/use-declarations.md [`Self` scope]: names/scopes.md#self-scope [`use`]: items/use-declarations.md [attributes]: attributes.md -[const generic argument]: generics.const.argument [enumeration]: items/enumerations.md [expressions]: expressions.md [extern prelude]: names/preludes.md#extern-prelude [implementation]: items/implementations.md -[inferred const]: generics.const.inferred [macro transcribers]: macros-by-example.md [macros]: macros.md [mbe]: macros-by-example.md diff --git a/src/types/generics/index.md b/src/types/generics/index.md index 35fdf7dc9b..8593a0d6e1 100644 --- a/src/types/generics/index.md +++ b/src/types/generics/index.md @@ -46,6 +46,81 @@ r[generics.parameters.builtin-generic-types] r[generics.parameters.invalid-lifetimes] `'_` and `'static` are not valid lifetime parameter names. +r[generics.arguments] +## Generic arguments + +r[generics.arguments.intro] +Generic arguments are the concrete values provided for generic parameters when using a parameterized item. They are specified in angle brackets (`<...>`) following the item's path (see [paths in types] and [paths in expressions]). Generic arguments can include lifetimes, types, and const values corresponding to the generic parameters declared on the item. + +```rust +struct Foo<'a, T, const N: usize> { + data: &'a [T; N], +} + +fn make_foo<'a, T, const N: usize>(data: &'a [T; N]) -> Foo<'a, T, N> { + Foo { data } +} + +// Generic arguments: lifetime 'static, type i32, const value 3. +let foo: Foo<'static, i32, 3> = Foo { data: &[1, 2, 3] }; +// Example of a call expression. +make_foo::(&[1, 2, 3]); +``` + +r[generics.arguments.syntax] +```grammar,paths +GenericArgs -> + `<` `>` + | `<` ( GenericArg `,` )* GenericArg `,`? `>` + +GenericArg -> + Lifetime | Type | GenericArgsConst | GenericArgsBinding | GenericArgsBounds + +GenericArgsConst -> + BlockExpression + | LiteralExpression + | `-` LiteralExpression + | SimplePathSegment + +GenericArgsBinding -> + IDENTIFIER GenericArgs? `=` Type + +GenericArgsBounds -> + IDENTIFIER GenericArgs? `:` Bounds +``` + +r[generics.arguments.argument-order] +The order of generic arguments is restricted to lifetime arguments, then type arguments, then const arguments, then equality constraints. + +r[generics.arguments.complex-const-params] +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[generics.arguments.impl-trait-params] +The synthetic type parameters corresponding to `impl Trait` types are implicit, and these cannot be explicitly specified. + r[generics.const] ## Const generics @@ -151,7 +226,7 @@ let _: S<1> = f::<(((_)))>(); // Inferred const. > 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[generics.const.inferred] -Where a const argument is expected, an `_` (optionally surrounded 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. +Where a const argument is expected, an `_` (optionally surrounded by any number of matching parentheses), called the *inferred const* ([generic argument rules][generics.arguments.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; N] { @@ -264,6 +339,8 @@ struct Foo<#[my_flexible_clone(unbounded)] H> { [literal]: expr.literal [path expression]: expr.path [path]: paths +[paths in expressions]: paths.expr +[paths in types]: paths.type [raw pointers]: type.pointer.raw [references]: type.pointer.reference [slices]: type.slice From 7fc1cf0b56df86e11a6b70d4914aa556fc6dde65 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 10 Feb 2026 14:30:11 -0800 Subject: [PATCH 08/24] Rewrite the paths in expressions intro This is just cleanup for clarity, and being more direct on what exactly they are. --- src/paths.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/paths.md b/src/paths.md index 7a3663e01a..cecb1851e7 100644 --- a/src/paths.md +++ b/src/paths.md @@ -53,7 +53,7 @@ PathIdentSegment -> ``` r[paths.expr.intro] -Paths in expressions allow for paths with generic arguments to be specified. They are used in various places in [expressions] and [patterns]. +Paths in expressions are used to refer to local variables and items, and they are also used in [patterns][patterns.path]. Optional [generic arguments] can be specified to supply concrete types, lifetimes, and constants for generic parameters. r[paths.expr.turbofish] The `::` token is required before the opening `<` for generic arguments to avoid ambiguity with the less-than operator. This is colloquially known as "turbofish" syntax. @@ -445,14 +445,13 @@ mod without { // crate::without [`use`]: items/use-declarations.md [attributes]: attributes.md [enumeration]: items/enumerations.md -[expressions]: expressions.md [extern prelude]: names/preludes.md#extern-prelude +[generic arguments]: generics.arguments [implementation]: items/implementations.md [macro transcribers]: macros-by-example.md [macros]: macros.md [mbe]: macros-by-example.md [module]: items/modules.md -[patterns]: patterns.md [struct]: items/structs.md [trait implementations]: items/implementations.md#trait-implementations [trait]: items/traits.md From a3f31f2d3ef9f37c1ce308309c20ec691f63f86d Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 10 Feb 2026 14:30:43 -0800 Subject: [PATCH 09/24] Add an introduction to the generics chapter This may not be terribly useful, but it felt awkward not having something here. --- src/types/generics/index.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/types/generics/index.md b/src/types/generics/index.md index 8593a0d6e1..2616913d01 100644 --- a/src/types/generics/index.md +++ b/src/types/generics/index.md @@ -1,6 +1,9 @@ r[generics] # Generics +r[generics.intro] +Generics allow items to be parameterized by types, lifetimes, and constants. This allows definitions to be written in a flexible way that can be reused with different concrete types and values. + r[generics.parameters] ## Generic parameters From f68d5b0a269a85d3ff0d03108b028ac2f692988a Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 28 Apr 2026 17:31:30 -0700 Subject: [PATCH 10/24] Rewrite generics.arguments.intro This rewrites the intro to be a little more precise about the different kinds of arguments. --- src/types/generics/index.md | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/types/generics/index.md b/src/types/generics/index.md index 2616913d01..8985f91377 100644 --- a/src/types/generics/index.md +++ b/src/types/generics/index.md @@ -53,22 +53,29 @@ r[generics.arguments] ## Generic arguments r[generics.arguments.intro] -Generic arguments are the concrete values provided for generic parameters when using a parameterized item. They are specified in angle brackets (`<...>`) following the item's path (see [paths in types] and [paths in expressions]). Generic arguments can include lifetimes, types, and const values corresponding to the generic parameters declared on the item. +Generic arguments are the concrete values provided for generic parameters and associated types when using a parameterized item. They are specified in angle brackets (`<...>`) following the item's path (see [paths in types] and [paths in expressions]). Generic arguments consist of: -```rust -struct Foo<'a, T, const N: usize> { - data: &'a [T; N], -} - -fn make_foo<'a, T, const N: usize>(data: &'a [T; N]) -> Foo<'a, T, N> { - Foo { data } -} +1. *Lifetime arguments* (e.g., `'a`) +2. *Type arguments* (e.g., `T`, `Vec`) +3. *Const arguments* (e.g., `{ N }`, `{ 1 + 2 }`) +4. *Infer arguments* (`_`) +5. *Associated item constraints* (e.g., `Item = T`, `Item: Bound`) -// Generic arguments: lifetime 'static, type i32, const value 3. -let foo: Foo<'static, i32, 3> = Foo { data: &[1, 2, 3] }; -// Example of a call expression. -make_foo::(&[1, 2, 3]); -``` +> [!EXAMPLE] +> ```rust +> # struct Foo<'a, T, const N: usize> { +> # data: &'a [T; N], +> # } +> # +> # fn make_foo<'a, T, const N: usize>(data: &'a [T; N]) -> Foo<'a, T, N> { +> # Foo { data } +> # } +> # +> // Generic arguments in a type path: lifetime 'static, type i32, const value 3. +> let foo: Foo<'static, i32, 3> = Foo { data: &[1, 2, 3] }; +> // Generic arguments in an expression path. +> make_foo::(&[1, 2, 3]); +> ``` r[generics.arguments.syntax] ```grammar,paths From 3319c1ecef7ac751a7ee671a201496cab13049be Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 28 Apr 2026 17:39:01 -0700 Subject: [PATCH 11/24] Add a dedicated section for generic const arguments This will cover the rules specific to arguments. --- src/expressions/array-expr.md | 2 +- src/types/generics/index.md | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/expressions/array-expr.md b/src/expressions/array-expr.md index 4a82a47614..519c85cc78 100644 --- a/src/expressions/array-expr.md +++ b/src/expressions/array-expr.md @@ -132,7 +132,7 @@ 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]: generics.const.argument +[const generic argument]: generics.const.arguments [const block expression]: expr.block.const [constant expression]: ../const_eval.md#constant-expressions [constant item]: ../items/constant-items.md diff --git a/src/types/generics/index.md b/src/types/generics/index.md index 8985f91377..f7bbe63340 100644 --- a/src/types/generics/index.md +++ b/src/types/generics/index.md @@ -209,9 +209,6 @@ fn bad_function() -> [u8; {N + 1}] { } ``` -r[generics.const.argument] -A const argument in a [path] specifies the const value to use for that item. - r[generics.const.argument.const-expr] 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). @@ -310,6 +307,12 @@ fn generic() { } ``` +r[generics.const.arguments] +### Const arguments + +r[generics.const.arguments.intro] +A *const argument* specifies the const value to use for a const parameter. + r[generics.parameters.attributes] ## Attributes From fb406a1f9281a1db2edb1ca9da811990115ecafc Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 28 Apr 2026 17:46:04 -0700 Subject: [PATCH 12/24] Move const argument rules into the const arguments section This moves generics.arguments.complex-const-params and generics.const.argument.const-expr to the const arguments section. These rules have been reworked to simplify how they are presented. --- src/types/generics/index.md | 82 +++++++++++++++---------------------- 1 file changed, 33 insertions(+), 49 deletions(-) diff --git a/src/types/generics/index.md b/src/types/generics/index.md index f7bbe63340..0080988979 100644 --- a/src/types/generics/index.md +++ b/src/types/generics/index.md @@ -102,32 +102,6 @@ GenericArgsBounds -> r[generics.arguments.argument-order] The order of generic arguments is restricted to lifetime arguments, then type arguments, then const arguments, then equality constraints. -r[generics.arguments.complex-const-params] -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[generics.arguments.impl-trait-params] The synthetic type parameters corresponding to `impl Trait` types are implicit, and these cannot be explicitly specified. @@ -209,29 +183,6 @@ fn bad_function() -> [u8; {N + 1}] { } ``` -r[generics.const.argument.const-expr] -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 -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[generics.const.inferred] Where a const argument is expected, an `_` (optionally surrounded by any number of matching parentheses), called the *inferred const* ([generic argument rules][generics.arguments.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. @@ -313,6 +264,39 @@ r[generics.const.arguments] r[generics.const.arguments.intro] A *const argument* specifies the const value to use for a const parameter. +r[generics.const.arguments.const-expr] +A const argument must either be an [inferred const] or be a [const expression] of the type ascribed to the const parameter. + +> [!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[generics.const.arguments.complex-const-params] +Const argument expressions must be surrounded by braces unless they are a [literal] (with a possibly leading `-` token) or a single segment path. + +> [!NOTE] +> This syntactic restriction is necessary to avoid requiring infinite lookahead when parsing an expression inside of a type. + +> [!EXAMPLE] +> ```rust +> 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. +> ``` +> +> ```rust,compile_fail +> fn f() -> [u8; N] { [0; _] } +> let _: [_; 1] = f::<{ _ }>(); +> // ^ ERROR `_` not allowed here +> ``` + r[generics.parameters.attributes] ## Attributes From 345774c980a12e3fd8b99238f65f3750f70d7e67 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 28 Apr 2026 17:48:45 -0700 Subject: [PATCH 13/24] Move generics.const.type-ambiguity to the generic const arguments section Move this rule to the arguments section since it is pertaining to arguments. --- src/types/generics/index.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/types/generics/index.md b/src/types/generics/index.md index 0080988979..75d4b908b3 100644 --- a/src/types/generics/index.md +++ b/src/types/generics/index.md @@ -212,21 +212,6 @@ fn f(x: [u8; N]) -> [u8; _] { x } // ^ ERROR not allowed ``` -r[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 in a block expression can force it to be interpreted as a const argument. - - - -```rust,compile_fail -type N = u32; -struct Foo; -// The following is an error, because `N` is interpreted as the type alias `N`. -fn foo() -> Foo { todo!() } // ERROR -// Can be fixed by wrapping in braces to force it to be interpreted as the `N` -// const parameter: -fn bar() -> Foo<{ N }> { todo!() } // ok -``` - r[generics.const.variance] Unlike type and lifetime parameters, const parameters can be declared without being used inside of a parameterized item, with the exception of implementations as described in [generic implementations]: @@ -297,6 +282,21 @@ Const argument expressions must be surrounded by braces unless they are a [liter > // ^ ERROR `_` not allowed here > ``` +r[generics.const.arguments.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 in a block expression can force it to be interpreted as a const argument. + + + +```rust,compile_fail +type N = u32; +struct Foo; +// The following is an error, because `N` is interpreted as the type alias `N`. +fn foo() -> Foo { todo!() } // ERROR +// Can be fixed by wrapping in braces to force it to be interpreted as the `N` +// const parameter: +fn bar() -> Foo<{ N }> { todo!() } // ok +``` + r[generics.parameters.attributes] ## Attributes From 6d50db0bd8a11abdb5c0821e426a01f5fb45d3b7 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 28 Apr 2026 18:11:26 -0700 Subject: [PATCH 14/24] Add "argument ordering and matching" This adds a whole section describing how generic arguments are matched with their parameters. --- src/types/generics/index.md | 130 +++++++++++++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 3 deletions(-) diff --git a/src/types/generics/index.md b/src/types/generics/index.md index 75d4b908b3..34165ee5c6 100644 --- a/src/types/generics/index.md +++ b/src/types/generics/index.md @@ -99,11 +99,133 @@ GenericArgsBounds -> IDENTIFIER GenericArgs? `:` Bounds ``` -r[generics.arguments.argument-order] -The order of generic arguments is restricted to lifetime arguments, then type arguments, then const arguments, then equality constraints. +### Argument ordering and matching + +r[generics.arguments.lifetime-order] +Lifetime arguments must appear before all other argument kinds. + +> [!EXAMPLE] +> ```rust,compile_fail +> struct Foo<'a, T> { +> data: &'a T, +> } +> +> // ERROR: lifetime argument `'static` must come before type argument `i32` +> let _: Foo; +> ``` + +r[generics.arguments.positional-matching] +Generic arguments are matched to generic parameters positionally: + +- The ith lifetime argument corresponds to the ith lifetime parameter. +- The ith type or const argument corresponds to the ith type or const parameter (counted together in declaration order). + +r[generics.arguments.constraint-order] +Associated item constraints must be listed after all other argument kinds, and may be listed in any order. + +> [!EXAMPLE] +> ```rust +> use std::fmt::Display; +> +> trait Container { +> type Item; +> type Error; +> } +> +> // Associated item constraints may be listed in any order relative to each other. +> fn process>(_: C) {} +> ``` + +> [!EXAMPLE] +> ```rust,compile_fail +> struct Foo<'a, T> { +> data: &'a T, +> } +> +> trait MyTrait { +> type Assoc; +> } +> +> // ERROR: associated item constraints must come after all other argument kinds. +> fn bad(_: &dyn MyTrait) where T: 'static {} +> let _: std::collections::HashMap; +> ``` + +r[generics.arguments.lifetime-elision] +Lifetime arguments may be omitted in the following cases: + +- When [lifetime elision] rules apply. +- In [turbofish] expressions (`::<...>`) where all lifetimes can be inferred. + +> [!EXAMPLE] +> ```rust +> struct Foo<'a, T> { +> data: &'a T, +> } +> +> fn make_foo<'a, T>(data: &'a T) -> Foo<'a, T> { +> Foo { data } +> } +> +> // Turbofish: lifetime arguments omitted because they can be inferred. +> let x = 42i32; +> let foo = make_foo::(&x); // `'_` lifetime argument elided in turbofish +> +> // Lifetime arguments omitted in a type annotation. +> let foo: Foo = Foo { data: &x }; +> ``` + +r[generics.arguments.all-lifetimes] +If any lifetime argument is provided, then all lifetime parameters must be specified. + +> [!EXAMPLE] +> ```rust,compile_fail +> struct Foo<'a, 'b, T> { +> x: &'a T, +> y: &'b T, +> } +> +> fn make_foo<'a, 'b, T>(x: &'a T, y: &'b T) -> Foo<'a, 'b, T> { +> Foo { x, y } +> } +> +> let a = 1i32; +> let b = 2i32; +> +> // OK: no lifetime arguments supplied (elided). +> let _: Foo = Foo { x: &a, y: &b }; +> // OK: all lifetime arguments supplied. +> let _: Foo<'static, 'static, i32> = Foo { x: &1, y: &2 }; +> // ERROR: only one of two lifetime arguments provided. +> let _: Foo<'static, i32> = Foo { x: &1, y: &b }; +> ``` + +r[generics.arguments.defaults] +Type and const parameters with default values need not be supplied. A parameter without a default cannot follow one with a default. + +When fewer arguments are supplied than parameters exist, the missing trailing arguments use their defaults if available, or are inferred if inference is enabled for that context. + +r[generics.arguments.self-param] +The `Self` parameter (when present, e.g., in [trait definitions][items.traits.self-param]) is implicit and cannot be explicitly specified. r[generics.arguments.impl-trait-params] -The synthetic type parameters corresponding to `impl Trait` types are implicit, and these cannot be explicitly specified. +Synthetic type parameters corresponding to `impl Trait` types are implicit and cannot be explicitly specified. + +r[generics.arguments.late-bound-lifetimes] +It is an error to provide explicit lifetime arguments when late-bound lifetimes are present. + +> [!EXAMPLE] +> ```rust,compile_fail +> fn foo<'a>(x: &'a str) -> &'a str { x } +> +> // ERROR: cannot specify late-bound lifetime arguments explicitly +> foo::<'static>("hello"); +> ``` + + r[generics.const] ## Const generics @@ -333,6 +455,7 @@ struct Foo<#[my_flexible_clone(unbounded)] H> { [inferred const]: generics.const.inferred [item declarations]: statement.item [item]: items +[lifetime elision]: lifetime-elision [literal]: expr.literal [path expression]: expr.path [path]: paths @@ -345,6 +468,7 @@ struct Foo<#[my_flexible_clone(unbounded)] H> { [trait object]: type.trait-object [traits]: items.traits [tuples]: type.tuple +[turbofish]: paths.expr.turbofish [type aliases]: items.type [unions]: items.union [value namespace]: names.namespaces From a65d48f15bb4f77d8a0e1cdf63e459ade0cec88e Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 28 Apr 2026 18:14:32 -0700 Subject: [PATCH 15/24] Add a section on inferred generic arguments This adds some rules explaining the basics of this. Of course the actual inference algorithm should eventually be described. --- src/types/generics/index.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/types/generics/index.md b/src/types/generics/index.md index 34165ee5c6..0a29069e52 100644 --- a/src/types/generics/index.md +++ b/src/types/generics/index.md @@ -227,6 +227,26 @@ FCW exists for non-value (function) position, see https://doc.rust-lang.org/nightly/rustc/lints/listing/warn-by-default.html#late-bound-lifetime-arguments --> +r[generics.arguments.inference] +### Infer arguments + +r[generics.arguments.inference.intro] +The placeholder `_` may be used for type or const arguments when the compiler can infer the value. + +> [!EXAMPLE] +> ```rust +> let v: Vec<_> = vec![1, 2, 3]; // _ inferred as i32 +> +> type T = [i32; N]; +> let x: T<_> = [1]; // _ inferred as 1 +> ``` + +> [!NOTE] +> The `_` placeholder cannot be used for lifetime arguments; use `'_` for elided lifetimes instead. + +r[generics.arguments.inference.parentheses] +Infer arguments may be surrounded by any number of matching parentheses. + r[generics.const] ## Const generics From d695a9a73b7b8b0b7f74cbf67ec1037ac64cc9e5 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 28 Apr 2026 18:16:58 -0700 Subject: [PATCH 16/24] Add "associated item constraints" This adds a section with rules describing associated item constraints. I'm not 100% certain this is the best chapter layout to place this section. Perhaps it should go somewhere else? I have intentionally used the terminology "associated item constraint" even though it is currently only *types* that are constrained. My intention is that once MCGA is stabilized, it will also include consts. --- src/types/generics/index.md | 80 +++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/src/types/generics/index.md b/src/types/generics/index.md index 0a29069e52..7c8e5d08a7 100644 --- a/src/types/generics/index.md +++ b/src/types/generics/index.md @@ -227,6 +227,82 @@ FCW exists for non-value (function) position, see https://doc.rust-lang.org/nightly/rustc/lints/listing/warn-by-default.html#late-bound-lifetime-arguments --> +r[generics.associated] +## Associated item constraints + +r[generics.associated.intro] +An *associated item constraint* constrains an [associated type] of a trait. There are two kinds of associated item constraints: equality constraints and bound constraints. + +r[generics.associated.equality] +An *equality constraint* fixes the associated item to a specific type. It is specified with the [GenericArgsBinding] syntax. + +> [!EXAMPLE] +> ```rust +> // The `Item` associated item is specified to be `i32`. +> fn sum_iter(iter: impl Iterator) -> i32 { +> iter.sum() +> } +> ``` + +r[generics.associated.bound] +A *bound constraint* requires the associated item to satisfy a [trait bound] without fixing it to a concrete type. It is specified with the [GenericArgsBounds] syntax. + +> [!EXAMPLE] +> ```rust +> # use std::fmt::Display; +> # +> // The `Item` associated type is required to implement Display. +> fn print_iter(iter: impl Iterator) { +> for item in iter { +> println!("{item}"); +> } +> } +> ``` + +r[generics.associated.constraints-position] +Associated item constraints are only permitted when the path refers to a [trait] in a type position. They are permitted in the following positions: + +- [Trait bounds], including inline bounds (`T: Trait`) and `where` clauses +- [`impl Trait`][impl trait] argument and return types +- [Trait object] types (`dyn Trait`) + +They are not permitted in the following positions: + +- On non-trait generic type paths such as structs, enums, or type aliases: `Struct` +- On the trait reference in an `impl` block header: `impl Trait for OtherType` +- On the trait segment of a [qualified path]: `>::AssocItem` +- On an associated item's path segment: `::AssocItem` +- In expression or method call [turbofish]: `Trait::::method()` or `value.method::()` + +> [!EXAMPLE] +> The following are invalid uses of associated item constraints: +> +> ```rust,compile_fail +> // ERROR: constraint on a non-trait generic type (struct). +> struct Container(T); +> fn f1() { +> let _: Container; +> } +> +> // ERROR: constraint on the trait reference in an `impl` block header. +> trait Produce { type Output; } +> struct Widget; +> impl Produce for Widget { +> type Output = i32; +> } +> +> // ERROR: constraint on the trait segment of a qualified type path. +> trait Source { type Data; } +> fn f3(_: &>::Data) {} +> +> // ERROR: constraint in an expression-position turbofish. +> trait Create { type Item; fn new() -> i32 { 0 } } +> fn f4() { Create::::new(); } +> +> // ERROR: constraint in a method call turbofish. +> fn f5() { 0u32.clone::(); } +> ``` + r[generics.arguments.inference] ### Infer arguments @@ -471,6 +547,7 @@ struct Foo<#[my_flexible_clone(unbounded)] H> { [generic implementations]: items.impl.generics [generic parameter scopes]: names.scopes.generic-parameters [higher-ranked lifetimes]: bound.higher-ranked +[impl trait]: type.impl-trait [implementations]: items.impl [inferred const]: generics.const.inferred [item declarations]: statement.item @@ -481,10 +558,13 @@ struct Foo<#[my_flexible_clone(unbounded)] H> { [path]: paths [paths in expressions]: paths.expr [paths in types]: paths.type +[qualified path]: paths.qualified [raw pointers]: type.pointer.raw [references]: type.pointer.reference [slices]: type.slice [structs]: items.struct +[trait bound]: bound +[Trait bounds]: bound [trait object]: type.trait-object [traits]: items.traits [tuples]: type.tuple From 86bcefd5d81c7f7fad6f1d540eda9c0870fedf85 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 28 Apr 2026 18:17:27 -0700 Subject: [PATCH 17/24] Fix generic attributes rule Attributes can go on any kind of generic parameter --- src/types/generics/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/generics/index.md b/src/types/generics/index.md index 7c8e5d08a7..4777886538 100644 --- a/src/types/generics/index.md +++ b/src/types/generics/index.md @@ -518,7 +518,7 @@ fn bar() -> Foo<{ N }> { todo!() } // ok r[generics.parameters.attributes] ## Attributes -Generic lifetime and type parameters allow [attributes] on them. There are no built-in attributes that do anything in this position, although custom derive attributes may give meaning to it. +Generic parameters allow [attributes] on them. There are no built-in attributes that do anything in this position, although custom derive attributes may give meaning to it. This example shows using a custom derive attribute to modify the meaning of a generic parameter. From 574a6bc834709a1cc953fb8e1acd40b1add484e3 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 3 Mar 2026 15:55:57 -0800 Subject: [PATCH 18/24] Add an example for const generics --- src/types/generics/index.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/types/generics/index.md b/src/types/generics/index.md index 4777886538..7b9e95022a 100644 --- a/src/types/generics/index.md +++ b/src/types/generics/index.md @@ -329,6 +329,26 @@ r[generics.const] r[generics.const.intro] *Const generic parameters* allow items to be generic over constant values. +> [!EXAMPLE] +> ```rust +> struct Grid { +> data: [[f32; WIDTH]; HEIGHT], +> } +> +> impl Grid { +> fn new() -> Self { +> Grid { data: [[0.0; WIDTH]; HEIGHT] } +> } +> +> fn size(&self) -> usize { +> WIDTH * HEIGHT +> } +> } +> +> let grid: Grid<4, 4> = Grid::new(); +> assert_eq!(grid.size(), 16); +> ``` + r[generics.const.namespace] The const identifier introduces a name in the [value namespace] for the constant parameter, and all instances of the item must be instantiated with a value of the given type. From 3250ddf33a07a3df362ae53a53c4181c5f41b3c9 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 3 Mar 2026 15:56:23 -0800 Subject: [PATCH 19/24] Move examples into example blocks --- src/types/generics/index.md | 192 +++++++++++++++++++----------------- 1 file changed, 99 insertions(+), 93 deletions(-) diff --git a/src/types/generics/index.md b/src/types/generics/index.md index 7b9e95022a..7f89e310dd 100644 --- a/src/types/generics/index.md +++ b/src/types/generics/index.md @@ -364,62 +364,64 @@ Const parameters can be used anywhere a [const item] can be used, with the excep 4. As a parameter to any type used in the body of any functions in the item. 5. As a part of the type of any fields in the item. -```rust -// Examples where const generic parameters can be used. - -// Used in the signature of the item itself. -fn foo(arr: [i32; N]) { - // Used as a type within a function body. - let x: [i32; N]; - // Used as an expression. - println!("{}", N * 2); -} - -// Used as a field of a struct. -struct Foo([i32; N]); - -impl Foo { - // Used as an associated constant. - const CONST: usize = N * 4; -} - -trait Trait { - type Output; -} - -impl Trait for Foo { - // Used as an associated type. - type Output = [i32; N]; -} -``` - -```rust,compile_fail -// Examples where const generic parameters cannot be used. -fn foo() { - // Cannot use in item definitions within a function body. - const BAD_CONST: [usize; N] = [1; N]; - static BAD_STATIC: [usize; N] = [1; N]; - fn inner(bad_arg: [usize; N]) { - let bad_value = N * 2; - } - type BadAlias = [usize; N]; - struct BadStruct([usize; N]); -} -``` +> [!EXAMPLE] +> ```rust +> // Examples where const generic parameters can be used. +> +> // Used in the signature of the item itself. +> fn foo(arr: [i32; N]) { +> // Used as a type within a function body. +> let x: [i32; N]; +> // Used as an expression. +> println!("{}", N * 2); +> } +> +> // Used as a field of a struct. +> struct Foo([i32; N]); +> +> impl Foo { +> // Used as an associated constant. +> const CONST: usize = N * 4; +> } +> +> trait Trait { +> type Output; +> } +> +> impl Trait for Foo { +> // Used as an associated type. +> type Output = [i32; N]; +> } +> ``` +> +> ```rust,compile_fail +> // Examples where const generic parameters cannot be used. +> fn foo() { +> // Cannot use in item definitions within a function body. +> const BAD_CONST: [usize; N] = [1; N]; +> static BAD_STATIC: [usize; N] = [1; N]; +> fn inner(bad_arg: [usize; N]) { +> let bad_value = N * 2; +> } +> type BadAlias = [usize; N]; +> struct BadStruct([usize; N]); +> } +> ``` r[generics.const.standalone] As a further restriction, const parameters may only appear as a standalone argument inside of a [type] or [array repeat expression]. In those contexts, they may only be used as a single segment [path expression], possibly inside a [block] (such as `N` or `{N}`). That is, they cannot be combined with other expressions. -```rust,compile_fail -// Examples where const parameters may not be used. - -// Not allowed to combine in other expressions in types, such as the -// arithmetic expression in the return type here. -fn bad_function() -> [u8; {N + 1}] { - // Similarly not allowed for array repeat expressions. - [1; {N + 1}] -} -``` +> [!EXAMPLE] +> ```rust,compile_fail +> // Examples where const parameters may not be used. +> +> // Not allowed to combine in other expressions in types, such as the +> // arithmetic expression in the return type here. +> fn bad_function() -> [u8; {N + 1}] { +> // Similarly not allowed for array repeat expressions. +> [1; {N + 1}] +> } +> ``` r[generics.const.inferred] Where a const argument is expected, an `_` (optionally surrounded by any number of matching parentheses), called the *inferred const* ([generic argument rules][generics.arguments.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. @@ -453,33 +455,35 @@ fn f(x: [u8; N]) -> [u8; _] { x } r[generics.const.variance] Unlike type and lifetime parameters, const parameters can be declared without being used inside of a parameterized item, with the exception of implementations as described in [generic implementations]: -```rust,compile_fail -// ok -struct Foo; -enum Bar { A, B } - -// ERROR: unused parameter -struct Baz; -struct Biz<'a>; -struct Unconstrained; -impl Unconstrained {} -``` +> [!EXAMPLE] +> ```rust,compile_fail +> // ok +> struct Foo; +> enum Bar { A, B } +> +> // ERROR: unused parameter +> struct Baz; +> struct Biz<'a>; +> struct Unconstrained; +> impl Unconstrained {} +> ``` r[generics.const.exhaustiveness] When resolving a trait bound obligation, the exhaustiveness of all implementations of const parameters is not considered when determining if the bound is satisfied. For example, in the following, even though all possible const values for the `bool` type are implemented, it is still an error that the trait bound is not satisfied: -```rust,compile_fail -struct Foo; -trait Bar {} -impl Bar for Foo {} -impl Bar for Foo {} - -fn needs_bar(_: impl Bar) {} -fn generic() { - let v = Foo::; - needs_bar(v); // ERROR: trait bound `Foo: Bar` is not satisfied -} -``` +> [!EXAMPLE] +> ```rust,compile_fail +> struct Foo; +> trait Bar {} +> impl Bar for Foo {} +> impl Bar for Foo {} +> +> fn needs_bar(_: impl Bar) {} +> fn generic() { +> let v = Foo::; +> needs_bar(v); // ERROR: trait bound `Foo: Bar` is not satisfied +> } +> ``` r[generics.const.arguments] ### Const arguments @@ -525,15 +529,16 @@ When there is ambiguity if a generic argument could be resolved as either a type -```rust,compile_fail -type N = u32; -struct Foo; -// The following is an error, because `N` is interpreted as the type alias `N`. -fn foo() -> Foo { todo!() } // ERROR -// Can be fixed by wrapping in braces to force it to be interpreted as the `N` -// const parameter: -fn bar() -> Foo<{ N }> { todo!() } // ok -``` +> [!EXAMPLE] +> ```rust,compile_fail +> type N = u32; +> struct Foo; +> // The following is an error, because `N` is interpreted as the type alias `N`. +> fn foo() -> Foo { todo!() } // ERROR +> // Can be fixed by wrapping in braces to force it to be interpreted as the `N` +> // const parameter: +> fn bar() -> Foo<{ N }> { todo!() } // ok +> ``` r[generics.parameters.attributes] ## Attributes @@ -542,15 +547,16 @@ Generic parameters allow [attributes] on them. There are no built-in attributes This example shows using a custom derive attribute to modify the meaning of a generic parameter. - -```rust,ignore -// Assume that the derive for MyFlexibleClone declared `my_flexible_clone` as -// an attribute it understands. -#[derive(MyFlexibleClone)] -struct Foo<#[my_flexible_clone(unbounded)] H> { - a: *const H -} -``` +> [!EXAMPLE] +> +> ```rust,ignore +> // Assume that the derive for MyFlexibleClone declared `my_flexible_clone` as +> // an attribute it understands. +> #[derive(MyFlexibleClone)] +> struct Foo<#[my_flexible_clone(unbounded)] H> { +> a: *const H +> } +> ``` [array repeat expression]: expr.array [arrays]: type.array From a6e34d83f50b7dced31ec323c6ec897e3795cbdc Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 3 Mar 2026 16:56:44 -0800 Subject: [PATCH 20/24] Document attributes on generic parameters This was stabilized in 1.37 (via https://github.com/rust-lang/rust/pull/61547), but the documentation here was never updated. There is a longer history of these being stabilized and then `cfg` being removed and then added again, see https://github.com/rust-lang/rust/issues/48848 https://github.com/rust-lang/rust/issues/51279 https://github.com/rust-lang/rust/pull/51283. --- src/types/generics/index.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/types/generics/index.md b/src/types/generics/index.md index 7f89e310dd..538121c5c5 100644 --- a/src/types/generics/index.md +++ b/src/types/generics/index.md @@ -541,28 +541,28 @@ When there is ambiguity if a generic argument could be resolved as either a type > ``` r[generics.parameters.attributes] -## Attributes +## Attributes on generic parameters -Generic parameters allow [attributes] on them. There are no built-in attributes that do anything in this position, although custom derive attributes may give meaning to it. - -This example shows using a custom derive attribute to modify the meaning of a generic parameter. +The [built-in attributes] that have meaning on a generic parameter are [`cfg`] and [the lint check attributes]. > [!EXAMPLE] -> -> ```rust,ignore -> // Assume that the derive for MyFlexibleClone declared `my_flexible_clone` as -> // an attribute it understands. -> #[derive(MyFlexibleClone)] -> struct Foo<#[my_flexible_clone(unbounded)] H> { -> a: *const H -> } +> ```rust +> use std::fmt::Debug; +> +> struct Wrapper< +> T, +> #[cfg(feature = "debug")] U: Debug, +> #[cfg(not(feature = "debug"))] U, +> > (T, U); > ``` +[`cfg`]: cfg.attr [array repeat expression]: expr.array [arrays]: type.array [associated const]: items.associated.const [associated type]: items.associated.type [block]: expr.block +[built-in attributes]: attributes.builtin [const contexts]: const-eval.const-context [const expression]: const-eval.const-expr [const generic argument]: generics.const.argument @@ -589,6 +589,7 @@ This example shows using a custom derive attribute to modify the meaning of a ge [references]: type.pointer.reference [slices]: type.slice [structs]: items.struct +[the lint check attributes]: attributes.diagnostics.lint [trait bound]: bound [Trait bounds]: bound [trait object]: type.trait-object From 25eea5f5d2c402ba01f7e4bb74477437d3b6f4e0 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 28 Apr 2026 12:26:32 -0700 Subject: [PATCH 21/24] Move "Infer arguments" up into the arguments section --- src/types/generics/index.md | 40 ++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/types/generics/index.md b/src/types/generics/index.md index 538121c5c5..db02ff5639 100644 --- a/src/types/generics/index.md +++ b/src/types/generics/index.md @@ -227,6 +227,26 @@ FCW exists for non-value (function) position, see https://doc.rust-lang.org/nightly/rustc/lints/listing/warn-by-default.html#late-bound-lifetime-arguments --> +r[generics.arguments.inference] +### Infer arguments + +r[generics.arguments.inference.intro] +The placeholder `_` may be used for type or const arguments when the compiler can infer the value. + +> [!EXAMPLE] +> ```rust +> let v: Vec<_> = vec![1, 2, 3]; // _ inferred as i32 +> +> type T = [i32; N]; +> let x: T<_> = [1]; // _ inferred as 1 +> ``` + +> [!NOTE] +> The `_` placeholder cannot be used for lifetime arguments; use `'_` for elided lifetimes instead. + +r[generics.arguments.inference.parentheses] +Infer arguments may be surrounded by any number of matching parentheses. + r[generics.associated] ## Associated item constraints @@ -303,26 +323,6 @@ They are not permitted in the following positions: > fn f5() { 0u32.clone::(); } > ``` -r[generics.arguments.inference] -### Infer arguments - -r[generics.arguments.inference.intro] -The placeholder `_` may be used for type or const arguments when the compiler can infer the value. - -> [!EXAMPLE] -> ```rust -> let v: Vec<_> = vec![1, 2, 3]; // _ inferred as i32 -> -> type T = [i32; N]; -> let x: T<_> = [1]; // _ inferred as 1 -> ``` - -> [!NOTE] -> The `_` placeholder cannot be used for lifetime arguments; use `'_` for elided lifetimes instead. - -r[generics.arguments.inference.parentheses] -Infer arguments may be surrounded by any number of matching parentheses. - r[generics.const] ## Const generics From 54aa24b3325b95136ee7a3c17b942dbe4168873e Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 24 Mar 2026 11:44:37 -0700 Subject: [PATCH 22/24] Move generic constants to a dedicated chapter --- src/SUMMARY.md | 1 + src/expressions/array-expr.md | 2 +- src/syntax-index.md | 2 +- src/types/generics/constants.md | 234 +++++++++++++++++++++++++++++++ src/types/generics/index.md | 235 +------------------------------- 5 files changed, 239 insertions(+), 235 deletions(-) create mode 100644 src/types/generics/constants.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 9493755c35..2d436f9563 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -93,6 +93,7 @@ - [Type parameters](types/parameters.md) - [Inferred type](types/inferred.md) - [Generics](types/generics/index.md) + - [Generic constants](types/generics/constants.md) - [Dynamically sized types](dynamically-sized-types.md) - [Type layout](type-layout.md) - [Interior mutability](interior-mutability.md) diff --git a/src/expressions/array-expr.md b/src/expressions/array-expr.md index 519c85cc78..3102f51b16 100644 --- a/src/expressions/array-expr.md +++ b/src/expressions/array-expr.md @@ -136,7 +136,7 @@ The array index expression can be implemented for types other than arrays and sl [const block expression]: expr.block.const [constant expression]: ../const_eval.md#constant-expressions [constant item]: ../items/constant-items.md -[inferred const]: generics.const.inferred +[inferred const]: generics.const.arguments.inferred [literal]: ../tokens.md#literals [memory location]: ../expressions.md#place-expressions-and-value-expressions [panic]: ../panic.md diff --git a/src/syntax-index.md b/src/syntax-index.md index f8edda6cf4..7ac9d87c96 100644 --- a/src/syntax-index.md +++ b/src/syntax-index.md @@ -340,7 +340,7 @@ This appendix provides an index of tokens and common forms with links to where t [if let]: expr.if.let [impl trait types]: type.impl-trait.return [implementations]: items.impl -[inferred const]: generics.const.inferred +[inferred const]: generics.const.arguments.inferred [inferred type]: type.inferred [infinite loop expressions]: expr.loop.infinite [infinite loops]: expr.loop.infinite diff --git a/src/types/generics/constants.md b/src/types/generics/constants.md new file mode 100644 index 0000000000..4b45957309 --- /dev/null +++ b/src/types/generics/constants.md @@ -0,0 +1,234 @@ +r[generics.const] +# Generic constants + +r[generics.const.intro] +*Generic constant parameters* allow items to be generic over constant values. + +> [!EXAMPLE] +> ```rust +> struct Grid { +> data: [[f32; WIDTH]; HEIGHT], +> } +> +> impl Grid { +> fn new() -> Self { +> Grid { data: [[0.0; WIDTH]; HEIGHT] } +> } +> +> fn size(&self) -> usize { +> WIDTH * HEIGHT +> } +> } +> +> let grid: Grid<4, 4> = Grid::new(); +> assert_eq!(grid.size(), 16); +> ``` + +r[generics.const.namespace] +The const identifier introduces a name in the [value namespace] for the constant parameter, and all instances of the item must be instantiated with a value of the given type. + +r[generics.const.allowed-types] +The only allowed types of const parameters are `u8`, `u16`, `u32`, `u64`, `u128`, `usize`, `i8`, `i16`, `i32`, `i64`, `i128`, `isize`, `char` and `bool`. + +r[generics.const.use] +Const parameters can be used anywhere a [const item] can be used, with the exception that when used in a [type] or [array repeat expression], it must be standalone (as described below). That is, they are allowed in the following places: + +1. As an applied const to any type which forms a part of the signature of the item in question. +2. As part of a const expression used to define an [associated const], or as a parameter to an [associated type]. +3. As a value in any runtime expression in the body of any functions in the item. +4. As a parameter to any type used in the body of any functions in the item. +5. As a part of the type of any fields in the item. + +> [!EXAMPLE] +> ```rust +> // Examples where generic constant parameters can be used. +> +> // Used in the signature of the item itself. +> fn foo(arr: [i32; N]) { +> // Used as a type within a function body. +> let x: [i32; N]; +> // Used as an expression. +> println!("{}", N * 2); +> } +> +> // Used as a field of a struct. +> struct Foo([i32; N]); +> +> impl Foo { +> // Used as an associated constant. +> const CONST: usize = N * 4; +> } +> +> trait Trait { +> type Output; +> } +> +> impl Trait for Foo { +> // Used as an associated type. +> type Output = [i32; N]; +> } +> ``` +> +> ```rust,compile_fail +> // Examples where generic constant parameters cannot be used. +> fn foo() { +> // Cannot use in item definitions within a function body. +> const BAD_CONST: [usize; N] = [1; N]; +> static BAD_STATIC: [usize; N] = [1; N]; +> fn inner(bad_arg: [usize; N]) { +> let bad_value = N * 2; +> } +> type BadAlias = [usize; N]; +> struct BadStruct([usize; N]); +> } +> ``` + +r[generics.const.standalone] +As a further restriction, const parameters may only appear as a standalone argument inside of a [type] or [array repeat expression]. In those contexts, they may only be used as a single segment [path expression], possibly inside a [block] (such as `N` or `{N}`). That is, they cannot be combined with other expressions. + +> [!EXAMPLE] +> ```rust,compile_fail +> // Examples where const parameters may not be used. +> +> // Not allowed to combine in other expressions in types, such as the +> // arithmetic expression in the return type here. +> fn bad_function() -> [u8; {N + 1}] { +> // Similarly not allowed for array repeat expressions. +> [1; {N + 1}] +> } +> ``` + +r[generics.const.variance] +Unlike type and lifetime parameters, const parameters can be declared without being used inside of a parameterized item, with the exception of implementations as described in [generic implementations]: + +> [!EXAMPLE] +> ```rust,compile_fail +> // ok +> struct Foo; +> enum Bar { A, B } +> +> // ERROR: unused parameter +> struct Baz; +> struct Biz<'a>; +> struct Unconstrained; +> impl Unconstrained {} +> ``` + +r[generics.const.exhaustiveness] +When resolving a trait bound obligation, the exhaustiveness of all implementations of const parameters is not considered when determining if the bound is satisfied. For example, in the following, even though all possible const values for the `bool` type are implemented, it is still an error that the trait bound is not satisfied: + +> [!EXAMPLE] +> ```rust,compile_fail +> struct Foo; +> trait Bar {} +> impl Bar for Foo {} +> impl Bar for Foo {} +> +> fn needs_bar(_: impl Bar) {} +> fn generic() { +> let v = Foo::; +> needs_bar(v); // ERROR: trait bound `Foo: Bar` is not satisfied +> } +> ``` + +r[generics.const.arguments] +## Const arguments + +r[generics.const.arguments.intro] +A *const argument* specifies the const value to use for a const parameter. + +r[generics.const.arguments.const-expr] +A const argument must either be an [inferred const] or be a [const expression] of the type ascribed to the const parameter. + +> [!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 [generic const argument]. + +r[generics.const.arguments.complex-const-params] +Const argument expressions must be surrounded by braces unless they are a [literal] (with a possibly leading `-` token) or a single segment path. + +> [!NOTE] +> This syntactic restriction is necessary to avoid requiring infinite lookahead when parsing an expression inside of a type. + +> [!EXAMPLE] +> ```rust +> 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. +> ``` +> +> ```rust,compile_fail +> fn f() -> [u8; N] { [0; _] } +> let _: [_; 1] = f::<{ _ }>(); +> // ^ ERROR `_` not allowed here +> ``` + +r[generics.const.arguments.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 in a block expression can force it to be interpreted as a const argument. + + + +> [!EXAMPLE] +> ```rust,compile_fail +> type N = u32; +> struct Foo; +> // The following is an error, because `N` is interpreted as the type alias `N`. +> fn foo() -> Foo { todo!() } // ERROR +> // Can be fixed by wrapping in braces to force it to be interpreted as the `N` +> // const parameter: +> fn bar() -> Foo<{ N }> { todo!() } // ok +> ``` + +r[generics.const.arguments.inferred] +## Inferred const arguments + +r[generics.const.arguments.inferred.intro] +An *inferred const* is a const argument specified with `_`. This asks the compiler to infer the const argument if possible based on surrounding information. + +> [!EXAMPLE] +> ```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[generics.const.arguments.inferred.signature] +The inferred const cannot be used in item signatures. + +> [!EXAMPLE] +> ```rust,compile_fail +> fn f(x: [u8; N]) -> [u8; _] { x } +> // ^ ERROR not allowed +> ``` + +[array repeat expression]: expr.array +[associated const]: items.associated.const +[associated type]: items.associated.type +[block]: expr.block +[const expression]: const-eval.const-expr +[const item]: items.const +[generic const argument]: generics.const.arguments +[generic implementations]: items.impl.generics +[inferred const]: generics.const.arguments.inferred +[literal]: expr.literal +[path expression]: expr.path +[value namespace]: names.namespaces diff --git a/src/types/generics/index.md b/src/types/generics/index.md index db02ff5639..f0a587acd5 100644 --- a/src/types/generics/index.md +++ b/src/types/generics/index.md @@ -2,7 +2,7 @@ r[generics] # Generics r[generics.intro] -Generics allow items to be parameterized by types, lifetimes, and constants. This allows definitions to be written in a flexible way that can be reused with different concrete types and values. +Generics allow items to be parameterized by types, lifetimes, and [constants]. This allows definitions to be written in a flexible way that can be reused with different concrete types and values. r[generics.parameters] ## Generic parameters @@ -323,223 +323,6 @@ They are not permitted in the following positions: > fn f5() { 0u32.clone::(); } > ``` -r[generics.const] -## Const generics - -r[generics.const.intro] -*Const generic parameters* allow items to be generic over constant values. - -> [!EXAMPLE] -> ```rust -> struct Grid { -> data: [[f32; WIDTH]; HEIGHT], -> } -> -> impl Grid { -> fn new() -> Self { -> Grid { data: [[0.0; WIDTH]; HEIGHT] } -> } -> -> fn size(&self) -> usize { -> WIDTH * HEIGHT -> } -> } -> -> let grid: Grid<4, 4> = Grid::new(); -> assert_eq!(grid.size(), 16); -> ``` - -r[generics.const.namespace] -The const identifier introduces a name in the [value namespace] for the constant parameter, and all instances of the item must be instantiated with a value of the given type. - -r[generics.const.allowed-types] -The only allowed types of const parameters are `u8`, `u16`, `u32`, `u64`, `u128`, `usize`, `i8`, `i16`, `i32`, `i64`, `i128`, `isize`, `char` and `bool`. - -r[generics.const.use] -Const parameters can be used anywhere a [const item] can be used, with the exception that when used in a [type] or [array repeat expression], it must be standalone (as described below). That is, they are allowed in the following places: - -1. As an applied const to any type which forms a part of the signature of the item in question. -2. As part of a const expression used to define an [associated const], or as a parameter to an [associated type]. -3. As a value in any runtime expression in the body of any functions in the item. -4. As a parameter to any type used in the body of any functions in the item. -5. As a part of the type of any fields in the item. - -> [!EXAMPLE] -> ```rust -> // Examples where const generic parameters can be used. -> -> // Used in the signature of the item itself. -> fn foo(arr: [i32; N]) { -> // Used as a type within a function body. -> let x: [i32; N]; -> // Used as an expression. -> println!("{}", N * 2); -> } -> -> // Used as a field of a struct. -> struct Foo([i32; N]); -> -> impl Foo { -> // Used as an associated constant. -> const CONST: usize = N * 4; -> } -> -> trait Trait { -> type Output; -> } -> -> impl Trait for Foo { -> // Used as an associated type. -> type Output = [i32; N]; -> } -> ``` -> -> ```rust,compile_fail -> // Examples where const generic parameters cannot be used. -> fn foo() { -> // Cannot use in item definitions within a function body. -> const BAD_CONST: [usize; N] = [1; N]; -> static BAD_STATIC: [usize; N] = [1; N]; -> fn inner(bad_arg: [usize; N]) { -> let bad_value = N * 2; -> } -> type BadAlias = [usize; N]; -> struct BadStruct([usize; N]); -> } -> ``` - -r[generics.const.standalone] -As a further restriction, const parameters may only appear as a standalone argument inside of a [type] or [array repeat expression]. In those contexts, they may only be used as a single segment [path expression], possibly inside a [block] (such as `N` or `{N}`). That is, they cannot be combined with other expressions. - -> [!EXAMPLE] -> ```rust,compile_fail -> // Examples where const parameters may not be used. -> -> // Not allowed to combine in other expressions in types, such as the -> // arithmetic expression in the return type here. -> fn bad_function() -> [u8; {N + 1}] { -> // Similarly not allowed for array repeat expressions. -> [1; {N + 1}] -> } -> ``` - -r[generics.const.inferred] -Where a const argument is expected, an `_` (optionally surrounded by any number of matching parentheses), called the *inferred const* ([generic argument rules][generics.arguments.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; 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[generics.parameters.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[generics.const.variance] -Unlike type and lifetime parameters, const parameters can be declared without being used inside of a parameterized item, with the exception of implementations as described in [generic implementations]: - -> [!EXAMPLE] -> ```rust,compile_fail -> // ok -> struct Foo; -> enum Bar { A, B } -> -> // ERROR: unused parameter -> struct Baz; -> struct Biz<'a>; -> struct Unconstrained; -> impl Unconstrained {} -> ``` - -r[generics.const.exhaustiveness] -When resolving a trait bound obligation, the exhaustiveness of all implementations of const parameters is not considered when determining if the bound is satisfied. For example, in the following, even though all possible const values for the `bool` type are implemented, it is still an error that the trait bound is not satisfied: - -> [!EXAMPLE] -> ```rust,compile_fail -> struct Foo; -> trait Bar {} -> impl Bar for Foo {} -> impl Bar for Foo {} -> -> fn needs_bar(_: impl Bar) {} -> fn generic() { -> let v = Foo::; -> needs_bar(v); // ERROR: trait bound `Foo: Bar` is not satisfied -> } -> ``` - -r[generics.const.arguments] -### Const arguments - -r[generics.const.arguments.intro] -A *const argument* specifies the const value to use for a const parameter. - -r[generics.const.arguments.const-expr] -A const argument must either be an [inferred const] or be a [const expression] of the type ascribed to the const parameter. - -> [!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[generics.const.arguments.complex-const-params] -Const argument expressions must be surrounded by braces unless they are a [literal] (with a possibly leading `-` token) or a single segment path. - -> [!NOTE] -> This syntactic restriction is necessary to avoid requiring infinite lookahead when parsing an expression inside of a type. - -> [!EXAMPLE] -> ```rust -> 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. -> ``` -> -> ```rust,compile_fail -> fn f() -> [u8; N] { [0; _] } -> let _: [_; 1] = f::<{ _ }>(); -> // ^ ERROR `_` not allowed here -> ``` - -r[generics.const.arguments.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 in a block expression can force it to be interpreted as a const argument. - - - -> [!EXAMPLE] -> ```rust,compile_fail -> type N = u32; -> struct Foo; -> // The following is an error, because `N` is interpreted as the type alias `N`. -> fn foo() -> Foo { todo!() } // ERROR -> // Can be fixed by wrapping in braces to force it to be interpreted as the `N` -> // const parameter: -> fn bar() -> Foo<{ N }> { todo!() } // ok -> ``` - r[generics.parameters.attributes] ## Attributes on generic parameters @@ -557,31 +340,18 @@ The [built-in attributes] that have meaning on a generic parameter are [`cfg`] a > ``` [`cfg`]: cfg.attr -[array repeat expression]: expr.array [arrays]: type.array -[associated const]: items.associated.const [associated type]: items.associated.type -[block]: expr.block [built-in attributes]: attributes.builtin -[const contexts]: const-eval.const-context -[const expression]: const-eval.const-expr -[const generic argument]: generics.const.argument -[const item]: items.const +[constants]: generics.const [enumerations]: items.enum [function pointers]: type.fn-pointer [functions]: items.fn -[generic implementations]: items.impl.generics [generic parameter scopes]: names.scopes.generic-parameters -[higher-ranked lifetimes]: bound.higher-ranked [impl trait]: type.impl-trait [implementations]: items.impl -[inferred const]: generics.const.inferred [item declarations]: statement.item -[item]: items [lifetime elision]: lifetime-elision -[literal]: expr.literal -[path expression]: expr.path -[path]: paths [paths in expressions]: paths.expr [paths in types]: paths.type [qualified path]: paths.qualified @@ -598,4 +368,3 @@ The [built-in attributes] that have meaning on a generic parameter are [`cfg`] a [turbofish]: paths.expr.turbofish [type aliases]: items.type [unions]: items.union -[value namespace]: names.namespaces From e6aa0f5e7041ec4bf5c82dbd398b80ca7ea97703 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 8 Apr 2026 13:30:23 -0700 Subject: [PATCH 23/24] Add a dedicated chapter for generic lifetimes This is only a bare-bones skeleton. The intent is that this should get filled out with more rules specific to generic lifetimes. --- book.toml | 1 + src/SUMMARY.md | 1 + src/types/generics/index.md | 3 ++- src/types/generics/lifetimes.md | 28 ++++++++++++++++++++++++++++ 4 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/types/generics/lifetimes.md diff --git a/book.toml b/book.toml index 42e9451b78..ceaa8c517b 100644 --- a/book.toml +++ b/book.toml @@ -51,6 +51,7 @@ use-boolean-and = true "/glossary.html#object-safe-traits" = "glossary.html#dyn-compatible-traits" "/items/extern-crates.html#extern-prelude" = "../names/preludes.html#extern-prelude" "/items/generics.html" = "../types/generics/index.html" +"/items/generics.html#generic-lifetimes" = "../types/generics/lifetimes.html" "/items/generics.html#where-clauses" = "../trait-bounds.html#where-clauses" "/items/modules.html#prelude-items" = "../names/preludes.html" "/items/traits.html#object-safety" = "traits.html#dyn-compatibility" diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 2d436f9563..291288b3f4 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -93,6 +93,7 @@ - [Type parameters](types/parameters.md) - [Inferred type](types/inferred.md) - [Generics](types/generics/index.md) + - [Generic lifetimes](types/generics/lifetimes.md) - [Generic constants](types/generics/constants.md) - [Dynamically sized types](dynamically-sized-types.md) - [Type layout](type-layout.md) diff --git a/src/types/generics/index.md b/src/types/generics/index.md index f0a587acd5..43b73b4189 100644 --- a/src/types/generics/index.md +++ b/src/types/generics/index.md @@ -2,7 +2,7 @@ r[generics] # Generics r[generics.intro] -Generics allow items to be parameterized by types, lifetimes, and [constants]. This allows definitions to be written in a flexible way that can be reused with different concrete types and values. +Generics allow items to be parameterized by types, [lifetimes], and [constants]. This allows definitions to be written in a flexible way that can be reused with different concrete types and values. r[generics.parameters] ## Generic parameters @@ -352,6 +352,7 @@ The [built-in attributes] that have meaning on a generic parameter are [`cfg`] a [implementations]: items.impl [item declarations]: statement.item [lifetime elision]: lifetime-elision +[lifetimes]: generics.lifetimes [paths in expressions]: paths.expr [paths in types]: paths.type [qualified path]: paths.qualified diff --git a/src/types/generics/lifetimes.md b/src/types/generics/lifetimes.md new file mode 100644 index 0000000000..360df84b29 --- /dev/null +++ b/src/types/generics/lifetimes.md @@ -0,0 +1,28 @@ +r[generics.lifetimes] +# Generic lifetimes + +r[generics.lifetimes.intro] +A *lifetime parameter* is a generic parameter for a lifetime. + +r[generics.lifetimes.at-least-once] +[Structs], [enumerations], and [unions] must use each of their lifetime parameters at least once in their fields or variants. + +> [!EXAMPLE] +> ```rust,compile_fail +> // ERROR: lifetime parameter `'a` is never used +> struct Foo<'a>; +> +> // ERROR: lifetime parameter `'a` is never used +> enum Bar<'a> { A } +> ``` +> +> ```rust +> // OK: `'a` appears in a field. +> struct Ref<'a, T> { +> r: &'a T, +> } +> ``` + +[enumerations]: items.enum +[structs]: items.struct +[unions]: items.union From 9f8f6ffd46a14d757ce5f5066926c54013f575ed Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 28 Apr 2026 12:01:42 -0700 Subject: [PATCH 24/24] Add a dedicated chapter for generic types This is only a bare-bones skeleton. The intent is that this should get filled out with more rules specific to generic types. --- src/SUMMARY.md | 1 + src/types/generics/index.md | 3 +- src/types/generics/types.md | 61 +++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 src/types/generics/types.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 291288b3f4..31eaa50974 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -94,6 +94,7 @@ - [Inferred type](types/inferred.md) - [Generics](types/generics/index.md) - [Generic lifetimes](types/generics/lifetimes.md) + - [Generic types](types/generics/types.md) - [Generic constants](types/generics/constants.md) - [Dynamically sized types](dynamically-sized-types.md) - [Type layout](type-layout.md) diff --git a/src/types/generics/index.md b/src/types/generics/index.md index 43b73b4189..0dd1dead5e 100644 --- a/src/types/generics/index.md +++ b/src/types/generics/index.md @@ -2,7 +2,7 @@ r[generics] # Generics r[generics.intro] -Generics allow items to be parameterized by types, [lifetimes], and [constants]. This allows definitions to be written in a flexible way that can be reused with different concrete types and values. +Generics allow items to be parameterized by [types], [lifetimes], and [constants]. This allows definitions to be written in a flexible way that can be reused with different concrete types and values. r[generics.parameters] ## Generic parameters @@ -368,4 +368,5 @@ The [built-in attributes] that have meaning on a generic parameter are [`cfg`] a [tuples]: type.tuple [turbofish]: paths.expr.turbofish [type aliases]: items.type +[types]: generics.types [unions]: items.union diff --git a/src/types/generics/types.md b/src/types/generics/types.md new file mode 100644 index 0000000000..f3ece2a995 --- /dev/null +++ b/src/types/generics/types.md @@ -0,0 +1,61 @@ +r[generics.types] +# Generic types + +r[generics.types.intro] +A *type parameter* is a generic parameter for a type. + +r[generics.types.at-least-once] +[Structs], [enumerations], and [unions] must use each of their type parameters at least once in their fields or variants. + +> [!EXAMPLE] +> ```rust,compile_fail +> // ERROR: type parameter `T` is never used +> struct Unused; +> +> // ERROR: type parameter `T` is never used +> enum Empty { A } +> ``` +> +> ```rust +> // OK: `T` appears in a field. +> struct Wrapper(T); +> +> // A type parameter that does not appear directly in any field may be used +> // via `std::marker::PhantomData`. +> struct Key { +> id: u64, +> _phantom: std::marker::PhantomData, +> } +> ``` + +r[generics.types.sized] +Unless the `?Sized` [opt-out bound][`Sized`] is present, a type parameter has an implicit [`Sized`] bound. This means the concrete type supplied for the parameter must have a size known at compile time. + +> [!EXAMPLE] +> ```rust +> // `T` implicitly requires `T: Sized`. +> fn takes_sized(x: T) {} +> +> // `T` may be a dynamically sized type. +> fn takes_unsized(x: &T) {} +> ``` + +r[generics.types.default-constraint] +The default type of a type parameter must satisfy all of the type parameter's [trait bounds]. + +> [!EXAMPLE] +> ```rust,compile_fail +> // ERROR: the default type `String` does not implement `Copy` +> struct Foo(T); +> ``` +> +> ```rust +> // OK: `i32` satisfies the `Copy` bound +> struct Bar(T); +> ``` + +[enumerations]: items.enum +[structs]: items.struct +[trait]: items.traits +[trait bounds]: bound +[unions]: items.union