Caution

You’re reading a draft of the Ferrocene Language Specification. Some parts of this document might be missing, incomplete or incorrect. Our aim is to have the specification ready by the end of 2022.

12. Generics

12.1. Generic Parameters

Syntax

GenericParameterList ::=
    < (GenericParameter (, GenericParameter)* ,?)? >

GenericParameter ::=
    OuterAttributeOrDoc* (
        ConstantParameter
      | LifetimeParameter
      | TypeParameter
    )

ConstantParameter ::=
   const Name TypeAscription (= ConstantParameterInitializer)?

ConstantParameterInitializer ::=
    BlockExpression
  | Identifier
  | -? LiteralExpression

LifetimeParameter ::=
    Lifetime (: LifetimeIndicationList)?

TypeParameter ::=
    Name (: TypeBoundList?)? (= TypeParameterInitializer)?

TypeParameterInitializer ::=
    TypeSpecification

Legality Rules

12.1:1 A generic parameter is a placeholder for a constant, a lifetime, or a type whose value is supplied statically by a generic argument.

12.1:2 It is a static error to use a generic parameter in the discriminant initializer of an enum variant.

12.1:3 All LifetimeParameters in a GenericParameterList shall precede all ConstantParameters and TypeParameters.

12.1:4 A sequence of LifetimeParameters shall be terminated by character 0x2C (comma) when followed by a ConstantParameter or a TypeParameter.

12.1:5 A generic enum is an enum with generic parameters.

12.1:6 A generic function is a function with generic parameters.

12.1:7 A generic implementation is an implementation with generic parameters.

12.1:8 A generic struct is a struct with generic parameters.

12.1:9 A generic trait is a trait with generic parameters.

12.1:10 A generic type alias is a type alias with generic parameters.

12.1:11 A generic union is a union with generic parameters.

12.1:12 A constant parameter is a generic parameter for a constant.

12.1:13 A constant parameter initializer is a construct that provides the default value of its related constant parameter.

12.1:14 A constant parameter initializer shall be a constant expression.

12.1:15 A lifetime parameter is a generic parameter for a lifetime.

12.1:16 A lifetime parameter shall not be used within a constant context, except for the 'static lifetime.

12.1:17 A type parameter is a generic parameter for a type.

12.1:18 A type parameter initializer is a construct that provides the default value of its related type parameter.

12.1:19 The type of the type parameter initializer of a type parameter shall satisfy the type bounds of the type parameter.

12.1:20 A generic enum shall use all of its type parameters and lifetime parameters at least once in at least one of its enum variants.

12.1:21 A generic struct shall use all of its type parameters and lifetime parameters at least once in at least one of its fields.

12.1:22 A generic union shall use all of its type parameters and lifetime parameters at least once in at least one of its fields.

12.1:23 A generic parameter is said to constrain an implementation if the generic parameter appears at least once in one of the following:

12.1:27 It is a static error if a type parameter or constant parameter of an implementation does not constrain the implementation.

12.1:28 It is a static error if a lifetime parameter of an implementation is used in an associated type without constraining the implementation.

12.1:29 The type of a constant parameter shall be a scalar type.

12.1:30 A constant parameter shall be used in the following contexts:

12.1:36 A type parameter has an implicit core::marker::Sized bound, unless a ?core::marker::Sized bound is present.

12.1:37 A type parameter of an abstract data type has implicit lifetime bounds depending on its usage in the fields of the abstract data type as follows:

12.1:40 A type parameter of a function has implicit lifetime bounds depending on its usages in the function parameters and return type as follows:

12.1:43 A generic parameter with a bound of the form

<X: Bound>

12.1:44 is equivalent to the generic parameter without the bound and a where clause of the following form:

where X: Bound

Examples

struct Array<T, const N: usize>([T; N])

fn generic_function<'a, T>() {}

struct Reference<'a, T: 'a> {
    the_reference: &'a T
}

12.2. Where Clauses

Syntax

WhereClause ::=
    where WhereClausePredicateList

WhereClausePredicateList ::=
    WhereClausePredicate (, WhereClausePredicate)* ,?

WhereClausePredicate ::=
    LifetimePredicate
  | TypeBoundPredicate

LifetimePredicate ::=
   LifetimeIndication : LifetimeIndicationList?

TypeBoundPredicate ::=
   ForGenericParameterList? TypeSpecification : TypeBoundList?

Legality Rules

12.2:1 A where clause is a construct that specifies bounds on lifetime parameters and type parameters.

12.2:2 A where clause predicate is a construct that specifies lifetime bounds on lifetime parameters as well as lifetime bounds and trait bounds on types.

12.2:3 A construct is valid when all of its where clause predicates hold true for the supplied generic arguments.

12.2:4 A trivial predicate is a where clause predicate that does not use the generic parameters or higher-ranked lifetimes of the related construct.

12.2:5 It is a static error to create a trivial predicate that does not hold.

Examples

struct Clause<T> where T: Iterator {
    field: T
}

12.3. Generic Arguments

Syntax

GenericArgumentList ::=
    < ( GenericArgument (, GenericArgument)* ,? )? >

GenericArgument ::=
    BindingArgument
  | ConstantArgument
  | LifetimeArgument
  | TypeArgument

BindingArgument ::=
    Identifier = TypeSpecification

ConstantArgument ::=
    BlockExpression
  | -? LiteralExpression
  | SimplePathSegment

LifetimeArgument ::=
    LifetimeIndication

TypeArgument ::=
    TypeSpecification

Legality Rules

12.3:1 A generic argument supplies a static input for an associated trait type or a generic parameter.

12.3:2 A BindingArgument shall follow ConstantArguments, LifetimeArguments, and TypeArguments in a GenericArgumentList.

12.3:3 A LifetimeArgument shall precede BindingArguments, ConstantArguments, and TypeArguments in a GenericArgumentList.

12.3:4 A constant argument is a generic argument that supplies the value of a constant parameter.

12.3:5 A type argument is a generic argument that supplies the type of a type parameter.

12.3:6 A lifetime argument is a generic argument that supplies the lifetime of a lifetime parameter.

12.3:7 A binding argument is a generic argument that supplies the type of an associated trait type.

12.3:8 A constant argument may only appear as a single segment path expression, optionally encapsulated in a block expression, within an array repetition constructor or a type.

12.3:9 Generic arguments are subject to generic conformance.

Examples

trait Trait {
    type Assoc;
}

12.3:10 The following is a generic function with a binding argument.

fn func<'lifetime, T, const C: usize>() where T: Trait<Assoc = usize> {}

12.3:11 The following are generic arguments for func.

func::<'static, u32, 0>();

12.4. Generic Conformance

Legality Rules

12.4:1 Generic conformance measures the compatibility between a set of generic parameters and a set of generic arguments.

12.4:2 A binding argument is conformant with an associated type when the supplied type of the binding argument fulfills the required trait bounds of the associated type.

12.4:3 A constant argument is conformant with a constant parameter when the types of the constant argument and constant parameter are unifiable.

12.4:4 A lifetime argument is conformant with a lifetime parameter when it outlives the lifetime specified by the lifetime parameter.

12.4:5 A type argument is conformant with a type parameter when the type of the type argument fulfills the required trait bounds of the type parameter.

12.4:6 Generic arguments are conformant with generic parameters when

12.4:11 Generic arguments shall be conformant.

12.4:12 The value of a constant parameter is determined as follows:

12.4:16 The value of a type parameter is determined as follows: