diff --git a/book.toml b/book.toml index 98697bf6c2..ceaa8c517b 100644 --- a/book.toml +++ b/book.toml @@ -50,6 +50,9 @@ 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/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" "/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..31eaa50974 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,10 @@ - [Impl trait type](types/impl-trait.md) - [Type parameters](types/parameters.md) - [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) - [Interior mutability](interior-mutability.md) 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..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]: items/generics.md#where-clauses +[where clauses]: bound.where diff --git a/src/expressions/array-expr.md b/src/expressions/array-expr.md index d0fe247635..3102f51b16 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.arguments [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.arguments.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..5a567db081 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]: bound.where [constant evaluation]: ../const_eval.md diff --git a/src/items/generics.md b/src/items/generics.md deleted file mode 100644 index 6161d11975..0000000000 --- a/src/items/generics.md +++ /dev/null @@ -1,310 +0,0 @@ -r[items.generics] -# Generic parameters - -r[items.generics.syntax] -```grammar,items -GenericParams -> `<` ( GenericParam (`,` GenericParam)* `,`? )? `>` - -GenericParam -> OuterAttribute* ( LifetimeParam | TypeParam | ConstParam ) - -LifetimeParam -> Lifetime ( `:` LifetimeBounds )? - -TypeParam -> IDENTIFIER ( `:` Bounds? )? ( `=` Type )? - -ConstParam -> - `const` IDENTIFIER `:` Type - ( `=` ( BlockExpression | IDENTIFIER | `-`?LiteralExpression ) )? -``` - -r[items.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] -The order of generic parameters is restricted to lifetime parameters and then type and const parameters intermixed. - -r[items.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: - -```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[items.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] -[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] -`'_` and `'static` are not valid lifetime parameter names. - -r[items.generics.const] -### Const generics - -r[items.generics.const.intro] -*Const generic parameters* allow items to be generic over constant values. - -r[items.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] -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] -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. - -```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[items.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}] -} -``` - -r[items.generics.const.argument] -A const argument in a [path] specifies the const value to use for that item. - -r[items.generics.const.argument.const-expr] -The argument must 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[items.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 -fn make_buf() -> [u8; N] { - [0; _] - // ^ Infers `N`. -} -let _: [u8; 1024] = make_buf::<_>(); -// ^ Infers `1024`. -``` - -> [!NOTE] -> An [inferred const] is not semantically an [expression][Expression] and so is not accepted within braces. -> -> ```rust,compile_fail -> fn f() -> [u8; N] { [0; _] } -> let _: [_; 1] = f::<{ _ }>(); -> // ^ ERROR `_` not allowed here -> ``` - -r[items.generics.const.inferred.constraint] -The inferred const cannot be used in item signatures. - -```rust,compile_fail -fn f(x: [u8; N]) -> [u8; _] { x } -// ^ ERROR not allowed -``` - -r[items.generics.const.type-ambiguity] -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[items.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 {} -``` - -r[items.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 -} -``` - -r[items.generics.where] -## Where clauses - -r[items.generics.where.syntax] -```grammar,items -WhereClause -> `where` ( WhereClauseItem `,` )* WhereClauseItem? - -WhereClauseItem -> - LifetimeWhereClauseItem - | TypeBoundWhereClauseItem - -LifetimeWhereClauseItem -> Lifetime `:` LifetimeBounds - -TypeBoundWhereClauseItem -> ForLifetimes? Type `:` Bounds? -``` - -r[items.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] -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[items.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. - -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 -} -``` - -[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 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..1375e8bb27 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]: bound.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..cecb1851e7 100644 --- a/src/paths.md +++ b/src/paths.md @@ -50,29 +50,10 @@ 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] -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. @@ -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,22 +440,18 @@ 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]: items.generics.const.argument [enumeration]: items/enumerations.md -[expressions]: expressions.md [extern prelude]: names/preludes.md#extern-prelude +[generic arguments]: generics.arguments [implementation]: items/implementations.md -[inferred const]: items.generics.const.inferred [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 diff --git a/src/syntax-index.md b/src/syntax-index.md index bb3d65c97e..7ac9d87c96 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.arguments.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]: 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 6a5b870c29..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` @@ -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` @@ -243,7 +277,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 +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]: items/generics.md#where-clauses +[where clause]: bound.where 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 new file mode 100644 index 0000000000..0dd1dead5e --- /dev/null +++ b/src/types/generics/index.md @@ -0,0 +1,372 @@ +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 + +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)* `,`? )? `>` + +GenericParam -> OuterAttribute* ( LifetimeParam | TypeParam | ConstParam ) + +LifetimeParam -> Lifetime ( `:` LifetimeBounds )? + +TypeParam -> IDENTIFIER ( `:` Bounds? )? ( `=` Type )? + +ConstParam -> + `const` IDENTIFIER `:` Type + ( `=` ( BlockExpression | IDENTIFIER | `-`?LiteralExpression ) )? +``` + +r[generics.parameters.decl-order] +The order of generic parameters is restricted to lifetime parameters and then type and const parameters intermixed. + +r[generics.parameters.duplicate-params] +The same parameter name may not be declared more than once in a [GenericParams] list. + +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.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.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 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: + +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`) + +> [!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 +GenericArgs -> + `<` `>` + | `<` ( GenericArg `,` )* GenericArg `,`? `>` + +GenericArg -> + Lifetime | Type | GenericArgsConst | GenericArgsBinding | GenericArgsBounds + +GenericArgsConst -> + BlockExpression + | LiteralExpression + | `-` LiteralExpression + | SimplePathSegment + +GenericArgsBinding -> + IDENTIFIER GenericArgs? `=` Type + +GenericArgsBounds -> + IDENTIFIER GenericArgs? `:` Bounds +``` + +### 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] +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.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 + +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.parameters.attributes] +## Attributes on generic parameters + +The [built-in attributes] that have meaning on a generic parameter are [`cfg`] and [the lint check attributes]. + +> [!EXAMPLE] +> ```rust +> use std::fmt::Debug; +> +> struct Wrapper< +> T, +> #[cfg(feature = "debug")] U: Debug, +> #[cfg(not(feature = "debug"))] U, +> > (T, U); +> ``` + +[`cfg`]: cfg.attr +[arrays]: type.array +[associated type]: items.associated.type +[built-in attributes]: attributes.builtin +[constants]: generics.const +[enumerations]: items.enum +[function pointers]: type.fn-pointer +[functions]: items.fn +[generic parameter scopes]: names.scopes.generic-parameters +[impl trait]: type.impl-trait +[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 +[raw pointers]: type.pointer.raw +[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 +[traits]: items.traits +[tuples]: type.tuple +[turbofish]: paths.expr.turbofish +[type aliases]: items.type +[types]: generics.types +[unions]: items.union 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 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