4. Types and Traits

4.1. Types

Syntax

TypeSpecification ::=
    ImplTraitTypeSpecification
  | TraitObjectTypeSpecification
  | TypeSpecificationWithoutBounds

TypeSpecificationList ::=
    TypeSpecification (, TypeSpecification)* ,?

TypeSpecificationWithoutBounds ::=
    ArrayTypeSpecification
  | FunctionPointerTypeSpecification
  | ImplTraitTypeSpecificationOneBound
  | InferredType
  | MacroInvocation
  | NeverType
  | ParenthesizedTypeSpecification
  | QualifiedTypePath
  | RawPointerTypeSpecification
  | ReferenceTypeSpecification
  | SliceTypeSpecification
  | TraitObjectTypeSpecificationOneBound
  | TupleTypeSpecification
  | TypePath

TypeAscription ::=
    : TypeSpecification

Legality Rules

4.1:1 A type defines a set of values and a set of operations that act on those values.

4.1:2 A local type is a type that is defined in the current crate.

4.2. Type Classification

Note

The contents of this section are informational.

Legality Rules

4.2:1 Types are organized in the following categories:

4.3. Scalar Types

4.3.1. Bool Type

Legality Rules

4.3.1:1 Bool is a type whose values denote the truth values of logic and Boolean algebra.

4.3.1:2 Type bool appears in the language prelude under the name bool.

4.3.1:3 Boolean value false has bit pattern 0x00. Boolean value true has bit pattern 0x01.

4.3.1:4 The following operations are defined on type bool:

4.3.1:5 Logical not

4.3.1:6

a

!a

4.3.1:7

true

false

4.3.1:8

false

true

4.3.1:9 Logical and

4.3.1:10

a

b

a & b

4.3.1:11

true

true

true

4.3.1:12

true

false

false

4.3.1:13

false

true

false

4.3.1:14

false

false

false

4.3.1:15 Logical or

4.3.1:16

a

b

a | b

4.3.1:17

true

true

true

4.3.1:18

true

false

true

4.3.1:19

false

true

true

4.3.1:20

false

false

false

4.3.1:21 Logical exclusive or (xor)

4.3.1:22

a

b

a ^ b

4.3.1:23

true

true

false

4.3.1:24

true

false

true

4.3.1:25

false

true

true

4.3.1:26

false

false

false

4.3.1:27 Equality

4.3.1:28

a

b

a == b

4.3.1:29

true

true

true

4.3.1:30

true

false

false

4.3.1:31

false

true

false

4.3.1:32

false

false

true

4.3.1:33 Greater than

4.3.1:34

a

b

a > b

4.3.1:35

true

true

false

4.3.1:36

true

false

true

4.3.1:37

false

true

false

4.3.1:38

false

false

false

4.3.1:39 Operation a != b is equivalent to !(a == b).

4.3.1:40 Operation a >= b is equivalent to a == b | a > b.

4.3.1:41 Operation a < b is equivalent to !(a >= b).

4.3.1:42 Operation a <= b is equivalent to a == b | a < b.

Undefined Behavior

4.3.1:43 It is a validity invariant for a value of type bool to have a bit pattern of 0x00 and 0x01.

4.3.2. Char Type

Legality Rules

4.3.2:1 Char is a type whose values are represented as a 32-bit unsigned word in the 0x000 - 0xD7FF or the 0xE000 - 0x10FFFF inclusive ranges of Unicode.

Undefined Behavior

4.3.2:2 It is a validity invariant for a value of type char to be inside the 0x000 - 0xD7FF or the 0xE000 - 0x10FFFF inclusive ranges of Unicode.

4.3.3. Numeric Types

4.3.3.1. Floating Point Types

Legality Rules

4.3.3.1:1 Type f32 is equivalent to the IEEE 754-2008 binary32 type.

4.3.3.1:2 Type f64 is equivalent to the IEEE 754-2008 binary64 type.

4.3.3.2. Integer Types

Legality Rules

4.3.3.2:1 Unsigned integer types define the following inclusive ranges over the domain of whole numbers:

4.3.3.2:2

Type

Minimum

Maximum

4.3.3.2:3

u8

0

28 - 1

4.3.3.2:4

u16

0

216 - 1

4.3.3.2:5

u32

0

232 - 1

4.3.3.2:6

u64

0

264 - 1

4.3.3.2:7

u128

0

2128 - 1

4.3.3.2:8 Type usize has the same number of bits as the platform’s pointer type, and is at least 16-bits wide.

4.3.3.2:9 Signed integer types define the following inclusive ranges over the domain of whole numbers:

4.3.3.2:10

Type

Minimum

Maximum

4.3.3.2:11

i8

- (27)

27 - 1

4.3.3.2:12

i16

- (215)

215 - 1

4.3.3.2:13

i32

- (231)

231 - 1

4.3.3.2:14

i64

- (263)

263 - 1

4.3.3.2:15

i128

- (2127)

2127 - 1

4.3.3.2:16 Type isize has the same number of bits as the platform’s pointer type, and is at least 16-bits wide.

4.4. Sequence Types

4.4.1. Array Types

Syntax

ArrayTypeSpecification ::=
    [ ElementType ; SizeOperand ]

ElementType ::=
    TypeSpecification

Legality Rules

4.4.1:1 An array type is a sequence type that represents a fixed sequence of elements.

4.4.1:2 The element type shall be a fixed sized type.

4.4.1:3 The size operand shall be a constant expression.

4.4.1:4 The type of the size operand is type usize.

Examples

4.4.1:5 An array type in the context of a let statement:

let array: [i32; 3] = [1, 2, 3];

4.4.2. Slice Types

Syntax

SliceTypeSpecification ::=
    [ ElementType ]

Legality Rules

4.4.2:1 A slice type is a sequence type that provides a view into a sequence of elements.

4.4.2:2 The element type shall be a fixed sized type.

4.4.2:3 A slice type is a dynamically sized type.

Examples

4.4.2:4 A slice type in the context of a let statement:

let array: [i32; 3] = [1, 2, 3];
let slice: &[i32] = &array[0..1];

4.4.3. Str Type

Legality Rules

4.4.3:1 Str is a sequence type that represents a slice of 8-bit unsigned bytes.

4.4.3:2 Type str is a dynamically sized type.

4.4.3:3 A value of type str shall denote a valid UTF-8 sequence of characters.

Undefined Behavior

4.4.3:4 It is a safety invariant for a value of type str to denote a valid UTF-8 sequence of characters.

4.4.4. Tuple Types

Syntax

TupleTypeSpecification ::=
    ( TupleFieldList? )

TupleFieldList ::=
    TupleField (, TupleField)* ,?

TupleField ::=
    TypeSpecification

Legality Rules

4.4.4:1 A tuple type is a sequence type that represents a heterogeneous list of other types.

4.4.4:2 If the type of a tuple field is a dynamically-sized type, then the tuple field shall be the last tuple field in the TupleFieldList.

Examples

()
(char,)
(i32, f64, Vec<String>)

4.5. Abstract Data Types

4.5.1. Enum Types

Syntax

EnumDeclaration ::=
    enum Name GenericParameterList? WhereClause? { EnumVariantList? }

EnumVariantList ::=
    EnumVariant (, EnumVariant)* ,?

EnumVariant ::=
    OuterAttributeOrDoc* VisibilityModifier? Name EnumVariantKind?

EnumVariantKind ::=
    DiscriminantInitializer
  | RecordStructFieldList
  | TupleStructFieldList

DiscriminantInitializer ::=
    = Expression

Legality Rules

4.5.1:1 An enum type is an abstract data type that contains enum variants.

4.5.1:2 A zero-variant enum type has no values.

4.5.1:3 An enum variant is a construct that declares one of the possible variations of an enum.

4.5.1:4 The name of an enum variant shall be unique within the related EnumDeclaration.

B.176:1 A discriminant is an opaque integer that identifies an enum variant.

4.5.1:6 A discriminant initializer shall be specified only when all enum variants appear without an EnumVariantKind.

4.5.1:7 The type of the expression of a discriminant initializer shall be either:

4.5.1:10 The value of the expression of a discriminant initializer shall be a constant expression.

4.5.1:11 The value of a discriminant of an enum variant is determined as follows:

  1. 4.5.1:12 If the enum variant contains a discriminant initializer, then the value is the value of its expression.

  2. 4.5.1:13 Otherwise, if the enum variant is the first enum variant in the EnumVariantList, then the value is zero.

  3. 4.5.1:14 Otherwise the value is one greater than the value of the discriminant of the previous enum variant.

4.5.1:15 It is a static error if two enum variants have discriminants with the same value.

4.5.1:16 It is a static error if the value of a discriminant exceeds the maximum value of the type of the expression of a discriminant initializer.

Undefined Behavior

4.5.1:17 It is a validity invariant for a value of an enum type to have a discriminant specified by the enum type.

Examples

enum ZeroVariantEnumType {}

enum Animal {
   Cat,
   Dog(String),
   Otter { name: String, weight: f64, age: u8 }
}

enum Discriminants {
    First,       // The discriminant is 0.
    Second,      // The discriminant is 1.
    Third = 12,  // The discriminant is 12.
    Fourth,      // The discriminant is 13.
    Fifth = 34,  // The discriminant is 34.
    Sixth        // The discriminant is 35.
}

4.5.2. Struct Types

Syntax

StructDeclaration ::=
    RecordStructDeclaration
  | TupleStructDeclaration
  | UnitStructDeclaration

RecordStructDeclaration ::=
    struct Name GenericParameterList? WhereClause? RecordStructFieldList

RecordStructFieldList ::=
    { (RecordStructField (, RecordStructField)* ,?)? }

RecordStructField ::=
    OuterAttributeOrDoc* VisibilityModifier? Name TypeAscription

TupleStructDeclaration ::=
    struct Name GenericParameterList? TupleStructFieldList WhereClause? ;

TupleStructFieldList ::=
    ( (TupleStructField (, TupleStructField)* ,?)? )

TupleStructField ::=
    OuterAttributeOrDoc* VisibilityModifier? TypeSpecification

UnitStructDeclaration ::=
    struct Name GenericParameterList? WhereClause? ;

Legality Rules

4.5.2:1 A struct type is an abstract data type that is a product of other types.

4.5.2:2 The name of a record struct field shall be unique within the related RecordStructDeclaration.

4.5.2:3 If the type of a record struct field is a dynamically sized type, then the record struct field shall be the last record struct field in the RecordStructFieldList.

4.5.2:4 If the type of a tuple struct field is a dynamically sized type, then the tuple struct field shall be the last tuple struct field in the TupleStructFieldList.

Examples

struct UnitStruct;

struct AnimalRecordStruct {
    name: String,
    weight: f64,
    age: u8
}

struct AnimalTupleStruct (
    String,
    f64,
    u8
);

4.5.3. Union Types

Syntax

UnionDeclaration ::=
    union Name GenericParameterList? WhereClause? RecordStructFieldList

Legality Rules

4.5.3:1 A union type is an abstract data type that is a sum of other types.

4.5.3:2 A union without any union fields is rejected, but may still be consumed by macros.

4.5.3:3 The name of a union field shall be unique within the related RecordStructDeclaration.

4.5.3:4 The type of a union field shall be either:

Examples

union LeafNode {
    int: i32,
    float: f32,
    double: f64
}

4.6. Function Types

4.6.1. Closure Types

Legality Rules

4.6.1:1 A closure type is a unique anonymous function type that encapsulates all capture targets of a closure expression.

4.6.1:2 A closure type implements the core::ops::FnOnce trait.

4.6.1:3 A closure type that does not move out its capture targets implements the core::ops::FnMut trait.

4.6.1:4 A closure type that does not move out or mutate its capture targets implements the core::ops::Fn trait.

4.6.1:5 A closure type that does not encapsulate capture targets is coercible to a function pointer type.

4.6.1:6 A closure type implicitly implements the core::marker::Copy trait if all the types of the values of the capturing environment implement the core::marker::Copy trait.

4.6.1:7 A closure type implicitly implements the core::clone::Clone trait if all the types of the values of the capturing environment implement the core::clone::Clone trait.

4.6.1:8 A closure type implicitly implements the core::marker::Send trait if all the types of the values of the capturing environment implement the core::marker::Send trait.

4.6.1:9 A closure type implicitly implements the core::marker::Sync trait if all the types of the values of the capturing environment implement the core::marker::Send trait.

4.6.2. Function Item Types

Legality Rules

4.6.2:1 A function item type is a unique anonymous function type that identifies a function.

4.6.2:2 An external function item type is a function item type where the related function is an external function.

4.6.2:3 An unsafe function item type is a function item type where the related function is an unsafe function.

4.6.2:4 A function item type is coercible to a function pointer type.

4.6.2:5 A function item type implements the core::clone::Clone trait, the core::marker::Copy trait, the core::ops::Fn trait, the core::ops::FnMut trait, the core::ops::FnOnce trait, the core::marker::Send trait, and the core::marker::Sync trait.

4.7. Indirection Types

4.7.1. Function Pointer Types

Syntax

FunctionPointerTypeSpecification ::=
    ForGenericParameterList? FunctionPointerTypeQualifierList fn
      ( FunctionPointerTypeParameterList? ) ReturnTypeWithoutBounds?

FunctionPointerTypeQualifierList ::=
    unsafe? AbiSpecification?

FunctionPointerTypeParameterList ::=
    FunctionPointerTypeParameter (, FunctionPointerTypeParameter)*
      (, VariadicPart | ,?)

VariadicPart ::=
    OuterAttributeOrDoc* ...

FunctionPointerTypeParameter ::=
    OuterAttributeOrDoc* (IdentifierOrUnderscore :)? TypeSpecification

Legality Rules

4.7.1:1 A function pointer type is an indirection type that refers to a function.

4.7.1:2 An unsafe function pointer type is a function pointer type subject to keyword unsafe.

4.7.1:3 A variadic part indicates the presence of C-like optional parameters.

4.7.1:4 A variadic part shall be specified only when the ABI of the function pointer type is either extern "C" or extern "cdecl".

4.7.1:5 The return type of a function pointer type is determined as follows:

Undefined Behavior

4.7.1:8 It is a validity invariant for a value of a function pointer type to be not null.

Examples

unsafe extern "C" fn (value: i32, ...) -> f64

4.7.2. Raw Pointer Types

Syntax

RawPointerTypeSpecification ::=
    * (const | mut) TypeSpecificationWithoutBounds

Legality Rules

4.7.2:1 A raw pointer type is an indirection type without validity guarantees.

4.7.2:2 A mutable raw pointer type is a raw pointer type subject to keyword mut.

4.7.2:3 An immutable raw pointer type is a raw pointer type subject to keyword const.

4.7.2:4 Comparing two values of raw pointer types compares the addresses of the values.

4.7.2:5 Comparing a value of a raw pointer type to a value of a dynamically sized type compares the data being pointed to.

Examples

*const i128
*mut bool

4.7.3. Reference Types

Syntax

ReferenceTypeSpecification ::=
    & LifetimeIndication? mut? TypeSpecificationWithoutBounds

Legality Rules

4.7.3:1 A reference type is an indirection type with ownership.

4.7.3:2 A shared reference type is a reference type not subject to keyword mut.

4.7.3:3 A shared reference type prevents the direct mutation of a referenced value.

4.7.3:4 A shared reference type implements the core::marker::Copy trait. Copying a shared reference performs a shallow copy.

4.7.3:5 Releasing a shared reference has no effect on the value it refers to.

4.7.3:6 A mutable reference type is a reference type subject to keyword mut.

4.7.3:7 A mutable reference type allows the direct mutation of a referenced value.

4.7.3:8 A mutable reference type does not implement the copy::marker::Copy trait.

Undefined Behavior

4.7.3:9 It is validity invariant for a value of a reference type to be not null.

Examples

&i16
&'a mut f32

4.8. Trait Types

4.8.1. Impl Trait Types

Syntax

ImplTraitTypeSpecification ::=
    impl TypeBoundList

ImplTraitTypeSpecificationOneBound ::=
    impl TraitBound

Legality Rules

4.8.1:1 An impl trait type is a type that implements a trait, where the type is known at compile time.

4.8.1:2 An impl trait type shall appear only within a function parameter or the return type of a function.

4.8.1:3 An anonymous return type is an impl trait type ascribed to a function return type.

4.8.1:4 An anonymous return type behaves as if it contained all declared type parameters of the return type‘s function and its parent trait or implementation.

4.8.1:5 An anonymous return type derived from an async function behaves as if it contained all declared type parameters and lifetime parameters of the return type‘s function and its parent trait or implementation.

4.8.1:6 An impl trait type shall not contain opt-out trait bounds.

Examples

fn anonymous_type_parameter
    (arg: impl Copy + Send + Sync) { ... }

fn anonymous_return_type () -> impl MyTrait { ... }

4.8.2. Trait Object Types

Syntax

TraitObjectTypeSpecification ::=
    dyn TypeBoundList

TraitObjectTypeSpecificationOneBound ::=
    dyn TraitBound

Legality Rules

4.8.2:1 A trait object type is a type that implements a trait, where the type is not known at compile time.

4.8.2:2 The principal trait of trait object type is the first trait bound.

4.8.2:3 The principal trait shall denote an object safe trait.

4.8.2:4 All non-principal trait trait bounds shall denote auto traits.

4.8.2:5 A trait object type shall not contain opt-out trait bounds.

4.8.2:6 A trait object type shall contain at most one lifetime bound.

4.8.2:7 A trait object type is a dynamically sized type. A trait object type permits late binding of methods. A method invoked via a trait object type involves dynamic dispatching.

Examples

dyn MyTrait
dyn MyTrait + Send
dyn MyTrait + 'static + Copy

4.9. Other Types

4.9.1. Inferred Types

Syntax

InferredType ::=
    _

Legality Rules

4.9.1:1 An inferred type is a placeholder for a type deduced by type inference.

4.9.1:2 An inferred type shall not appear in the following positions:

4.9.1:7 An inferred type forces a tool to deduce a type, if possible.

Examples

let values: Vec<_> = (0 .. 10).collect();

4.9.2. Type Parameters

Legality Rules

4.9.2:1 A type parameter type is a placeholder type of a type parameter to be substituted by generic substitution.

Examples

fn type_parameter<T>(parameter: T) {}

4.9.3. Never Type

Syntax

NeverType ::=
    !

Legality Rules

4.9.3:1 The never type is a type that represents the result of a computation that never completes.

4.9.3:2 The never type has no values.

Undefined Behavior

4.9.3:3 It is validity invariant to not have a value of the never type.

Examples

let never_completes: ! = panic!();

4.9.4. Parenthesized Types

Syntax

ParenthesizedTypeSpecification ::=
    ( TypeSpecification )

Legality Rules

4.9.4:1 A parenthesized type is a type that disambiguates the interpretation of lexical elements.

Examples

&'a (dyn MyTrait + Send)

4.10. Type Aliases

Syntax

TypeAliasDeclaration ::=
    type Name GenericParameterList? (: TypeBoundList)? WhereClause?
      (= InitializationType WhereClause?)? ;

InitializationType ::=
    TypeSpecification

Legality Rules

4.10:1 A type alias is an item that defines a name for a type.

4.10:2 A type alias shall not have a TypeBoundList unless it is an associated item.

4.10:3 The last where clause is rejected, but may still be consumed by macros.

Examples

type Point = (f64, f64);

4.11. Representation

4.11.1. Type Layout

Legality Rules

4.11.1:1 All values have an alignment and a size.

4.11.1:2 The alignment of a value specifies which addresses are valid for storing the value. Alignment is measured in bytes, is at least one, and always a power of two. A value of alignment N is stored at an address that is a multiple of N.

4.11.1:3 The size of a type is the offset in bytes between successive elements in array type [T, N] where T is the type of the value, including any padding for alignment. Size is a multiple of the alignment.

4.11.1:4 The size of scalar types is as follows:

4.11.1:5

Type

Size

4.11.1:6

bool

1

4.11.1:7

u8, i8

1

4.11.1:8

u16, i16

2

4.11.1:9

u32, i32

4

4.11.1:10

u64, i64

8

4.11.1:11

u128, i128

16

4.11.1:12

f32

4

4.11.1:13

f64

8

4.11.1:14

char

4

4.11.1:15 Types usize and isize have size big enough to contain every address on the target platform.

4.11.1:16 For type str, the layout is that of slice type [u8].

4.11.1:17 For array type [T; N] where T is the element type and N is size operand, the alignment is that of T, and the size is calculated as core::mem::size_of::<T>() * N.

4.11.1:18 For a slice type, the layout is that of the array type it slices.

4.11.1:19 For a tuple type, the layout is tool-defined. For a unit tuple, the size is zero and the alignment is one.

4.11.1:20 For a closure type, the layout is tool-defined.

4.11.1:21 For a thin pointer, the size and alignment are those of type usize.

4.11.1:22 For a function pointer type, the size and alignment are those of a thin pointer.

4.11.1:23 For a fat pointer, the size and alignment are tool-defined, but are at least those of a thin pointer.

4.11.1:24 For a trait object type, the layout is the same as the value being coerced into the trait object type at runtime.

4.11.1:25 For a struct type, the memory layout is undefined, unless the struct type is subject to attribute repr.

4.11.1:26 For a union type, the memory layout is undefined, unless the union type is subject to attribute repr. All union fields share a common storage.

4.11.1:27 The size of a recursive type shall be finite.

4.11.2. Type Representation

Legality Rules

4.11.2:1 Type representation specifies the layout of fields of abstract data types. Type representation changes the bit padding between fields of abstract data types as well as their order, but does not change the layout of the fields themselves.

4.11.2:2 Type representation is classified into:

4.11.2:7 C representation lays out a type such that the type is interoperable with the C language.

4.11.2:8 Default representation makes no guarantees about the layout.

4.11.2:9 Primitive representation is the type representation of individual integer types. Primitive representation applies only to an enum type that is not a zero-variant enum type. It is possible to combine C representation and primitive representation.

4.11.2:10 Transparent representation applies only to an enum type with a single enum variant or a struct type where the struct type or enum variant has a single field of non-zero size and any number of fields of size zero and alignment one.

4.11.2:11 Types subject to transparent representation have the same type representation as the type of their field with non-zero size.

4.11.2:12 Type representation may be specified using attribute repr. An enum type, a struct type, or a union type that is not subject to attribute repr has default representation.

4.11.2:13 Type representation may be specified using attribute repr and modified further using attribute repr‘s Alignment representation modifiers. A representation modifier shall apply only to a struct type or a union type subject to C representation or default representation.

4.11.2.1. Enum Type Representation

Legality Rules

4.11.2.1:1 Zero-variant enum types shall not be subject to C representation.

4.11.2.1:2 The size and alignment of an enum type without fields subject to C representation, default representation, or primitive representation are those of its discriminant.

4.11.2.1:3 The discriminant type of an enum type with C representation is the corresponding c signed int type for the target platform’s C ABI.

4.11.2.1:4 The discriminant type of an enum type with default representation is tool-defined.

4.11.2.1:5 The discriminant type of an enum type with primitive representation is the integer type specified by the primitive representation.

4.11.2.1:6 It is a static error if the discriminant type cannot hold all the discriminant values of an enum type.

4.11.2.1:7 An enum type subject to transparent representation shall have a single enum variant with

4.11.2.1:10 An enum type subject to C representation or primitive representation has the same type representation as a union type with C representation that is laid out as follows:

4.11.2.1:14 An enum type subject to transparent representation has the same type representation as the single field of non-zero size of its enum variant if one is present, otherwise the enum type has size zero and alignment one.

4.11.2.2. Struct Type Representation

Legality Rules

4.11.2.2:1 The alignment of a struct type subject to C representation is the alignment of the most-aligned field in it.

4.11.2.2:2 The size of a struct type subject to C representation is determined as follows:

  1. 4.11.2.2:3 Initialize a current offset to zero.

  2. 4.11.2.2:4 For each field of the struct type in declarative order:

    1. 4.11.2.2:5 Calculate the size and alignment of the field.

    2. 4.11.2.2:6 If the current offset is not a multiple of the field's alignment, add byte padding to the current offset until it is a multiple of the alignment. The offset of the field is the current offset.

    3. 4.11.2.2:7 Increase the current offset by the size of the field.

    4. 4.11.2.2:8 Proceed with the next field.

  3. 4.11.2.2:9 Round up the current offset to the nearest multiple of the struct type's alignment.

  4. 4.11.2.2:10 The size of the struct type is the current offset.

4.11.2.2:11 A struct type subject to transparent representation shall have:

4.11.2.2:14 A struct type subject to transparent representation has the same type representation as the single field of non-zero size if one is present, otherwise the struct type has size zero and alignment one.

4.11.2.3. Union Type Representation

Legality Rules

4.11.2.3:1 The size of a union type subject to C representation is the maximum of the sizes of all its fields, rounded up to alignment of the union type.

4.11.2.3:2 The alignment of a union type subject to C representation is the maximum of the alignments of all of its fields.

4.12. Type Model

4.12.1. Recursive Types

Legality Rules

4.12.1:1 A recursive type is a type whose contained types refer back to the containing type, either directly or by referring to another type which refers back to the original recursive type.

4.12.1:2 A type that is not an abstract data type shall not be recursive.

Examples

enum List<T> {
    Nil,
    Cons(T, Box<List<T>>)
}

4.12.2. Type Unification

Legality Rules

4.12.2:1 Type unification is the process by which type inference propagates known types across the type inference root and assigns concrete types to type variables, as well as a general mechanism to check for compatibility between two types during method resolution.

4.12.2:2 A type is said to unify with another type when the domains, ranges, and structures of both types are compatible according to the rules detailed below.

4.12.2:3 Two types that unify are said to be unifiable types.

4.12.2:4 Type unification is a symmetric operation. If type A unifies with type B, then B also unifies with A and such type unification results in the same observable effects.

4.12.2:5 If one of the two types is a type variable, type unification proceeds as follows:

  1. 4.12.2:6 If either type is a global type variable, the global type variable is assigned the type of the other unification operand.

  2. 4.12.2:7 Otherwise, if either type is a diverging type variable, the diverging type variable is assigned the type of the other unification operand.

  3. 4.12.2:8 Otherwise, if one type T is an integer type variable, behavior depends on the other type U:

    1. 4.12.2:9 If U is an integer type or an integer type variable, the integer type variable T is assigned type U.

    2. 4.12.2:10 Otherwise, type unification fails.

  4. 4.12.2:11 Otherwise, if one type T is a floating-point type variable, behavior depends on the other type U:

    1. 4.12.2:12 If U is a floating-point type or an floating-point type variable, the floating-point type variable T is assigned type U.

    2. 4.12.2:13 Otherwise, type unification fails.

  5. 4.12.2:14 Otherwise, neither type is a type variable, and the rules below are in effect.

4.12.2:15 A scalar type is unifiable only with itself.

4.12.2:16 The never type is unifiable with any other type.

4.12.2:17 An array type is unifiable only with another array type when

4.12.2:20 A slice type is unifiable only with another slice type when the element types of both slice types are unifiable.

4.12.2:21 Type str is unifiable only with itself.

4.12.2:22 A tuple type is unifiable only with another tuple type when:

4.12.2:25 An abstract data type is unifiable only with another abstract data type when:

4.12.2:28 A closure type is unifiable only with another closure type when:

4.12.2:31 A function item type is unifiable only with another function item type when:

4.12.2:34 A function pointer type is unifiable only with another function pointer type when:

4.12.2:42 A raw pointer type is unifiable only with another raw pointer type when:

4.12.2:45 A reference type is unifiable only with another reference type when:

4.12.2:48 An anonymous return type is unifiable with another type when:

4.12.2:51 An impl trait type is unifiable only with itself.

4.12.2:52 A trait object type is unifiable only with another trait object type when:

  • 4.12.2:53 The bounds are unifiable, and

  • 4.12.2:54 The lifetimes are unifiable.

4.12.2:55 A type alias is unifiable with another type when the aliased type is unifiable with the other type.

4.12.3. Type Coercion

Legality Rules

4.12.3:1 Type coercion is an implicit operation that changes the type of a value. Any implicit conversion allowed by type coercion can be made explicit using a type cast expression.

4.12.3:2 A type coercion takes place at a coercion site or within a coercion-propagating expression.

4.12.3:3 The following constructs constitute a coercion site:

4.12.3:10 The following expressions constitute a coercion-propagating expression:

4.12.3:15 Type coercion from a source type to a target type is allowed to occur when:

4.12.3:30 An unsized coercion is a type coercion that converts a sized type into an unsized type. Unsized coercion from a source type to a target type is allowed to occur when:

  • 4.12.3:31 The source type is array type [T; N] and the target type is slice type [T].

  • 4.12.3:32 The source type is T and the target type is dyn U, where T implements U + core::marker::Sized, and U is object safe.

  • 4.12.3:33 The source type is

S<..., T, ...> {
    ...
    last_field: X
}

4.12.3:34 where

  • 4.12.3:35 S is a struct type,

  • 4.12.3:36 T implements core::marker::Unsize<U>,

  • 4.12.3:37 last_field is a struct field of S,

  • 4.12.3:38 The type of last_field involves T and if the type of last_field is W<T>, then W<T> implements core::marker::Unsize<W<U>>,

  • 4.12.3:39 T is not part of any other struct field of S.

4.12.3:40 and the target type is S<..., U, ...>.

4.12.3:41 Least upper bound coercion is a multi-type coercion that is used in the following scenarios:

4.12.3:48 Least upper bound coercion considers a set of source types T1, T2, ..., TN and target type U. The target type is obtained as follows:

  1. 4.12.3:49 Initialize target type U to source type T1.

  2. 4.12.3:50 For each current source type TC in the inclusive range T1 to TN

    1. 4.12.3:51 If TC can be coerced to U, then continue with the next source type.

    2. 4.12.3:52 Otherwise, if U can be coerced to TC, make TC the target type U.

    3. 4.12.3:53 Otherwise, if TC and U are non-capturing closure types, function item types, function pointer types, or a combination of those types, and a function pointer type exists that both TC and U can coerce to, make that function pointer type be target type U.

    4. 4.12.3:54 Otherwise, no coercion is performed.

    5. 4.12.3:55 Continue with the next source type.

4.12.4. Structural Equality

Legality Rules

4.12.4:1 A type is structurally equal when its values can be compared for equality by structure.

4.12.4:2 The following types are structurally equal:

4.12.5. Interior Mutability

Legality Rules

4.12.5:1 Interior mutability is a property of types whose values can be modified through immutable references.

4.12.5:2 A type is subject to interior mutability when it contains a core::cell::UnsafeCell.

4.12.6. Type Inference

Legality Rules

4.12.6:1 Type inference is the process of automatically determining the type of expressions and patterns within a type inference root.

4.12.6:2 A type inference root is an expression whose inner expressions and patterns are subject to type inference independently of those found in other type inference roots.

4.12.6:3 The following expressions are considered type inference roots:

4.12.6:12 A type inference root imposes an expected type on its expression depending on the type inference root as follows:

4.12.6:21 A type variable is a placeholder used during type inference to stand in for an undetermined type of an expression or a pattern.

4.12.6:22 A global type variable is a type variable that can refer to any type.

4.12.6:23 An integer type variable is a type variable that can refer only to integer types.

4.12.6:24 A floating-point type variable is a type variable that can refer only to floating-point types.

4.12.6:25 A diverging type variable is a type variable that can refer to any type and originates from a diverging expression.

4.12.6:26 A lifetime variable is a placeholder used during type inference to stand in for an undetermined lifetime of a type.

4.12.6:27 The type inference algorithm uses type unification to propagate known types of expressions and patterns across the type inference root being inferred. In the rules detailed below, a static error occurs when type unification fails.

4.12.6:28 Performing type inference may introduce a requirement that some type must implement a trait, or that a type or lifetime must outlive some other lifetime. Such requirements are referred to as obligations and are detailed in the inference rules below.

4.12.6:29 If insufficient type information is available at the time an obligation is introduced, it may be deferred to be resolved later. Any time new type information is derived during type inference, the tool attempts to resolve all outstanding obligations and propagate any resulting type information via type unification.

4.12.6:30 When an associated type <Type as Trait>::Assoc is referenced within a type inference root (either explicitly within the source code, or via the inferece rules below), an obligation requiring that Type implements Trait is introduced.

4.12.6:31 Type inference for a type inference root proceeds as follows:

  1. 4.12.6:32 Recursively process all expressions and statements in the type inference root in program order.

    1. 4.12.6:33 For each statement, apply the statement inference rules outlined below.

    2. 4.12.6:34 For each expression, apply the expression inference rules outlined below.

  2. 4.12.6:35 If there are any remaining integer type variables that have not been unified with a concrete integer type, perform integer type fallback by unifying them with i32.

  3. 4.12.6:36 If there are any remaining floating-point type variables that have not been unified with a concrete floating-point type, perform floating-point type fallback by unifying them with f64.

  4. 4.12.6:37 If there are any remaining diverging type variables that have not been unified with a concrete type, unify them with the unit type.

  5. 4.12.6:38 If there are any remaining global type variables that have not been unified with a concrete type, raise a static error.

  6. 4.12.6:39 If there are any remaining obligations that do not hold or cannot be resolved with the available type information, raise a static error.

4.12.6:40 The type inference rules for statements are as follows:

4.12.6:47 Type inference of expressions may incorporate an expected type, derived from the context the expression appears in. If the expression is a coercion site or a coercion-propagating expression, the type derived via type inference may be coerced to the expected type. If no type coercion to the expected type is possible, or the expression is not a coercion site or a coercion-propagating expression, the inferred expression type is unified with the expected type.

4.12.6:48 The type inference rules for expressions are as follows:

4.12.6:106 If an expression is a diverging expression, its type is a new diverging type variable.

4.13. Traits

Syntax

TraitDeclaration ::=
    unsafe? trait Name GenericParameterList? (: SupertraitList?)? WhereClause? TraitBody

SupertraitList ::=
    TypeBoundList

TraitBody ::=
    {
      InnerAttributeOrDoc*
      AssociatedItem*
    }

Legality Rules

4.13:1 A trait is an item that describes an interface a type can implement.

4.13:2 A trait body is a construct that encapsulates the associated items, inner attributes, and inner doc comments of a trait.

4.13:3 Within a trait, the type Self acts as a placeholder for a type implementing the trait, and behaves like a type parameter.

4.13:4 A local trait is a trait that is defined in the current crate.

B.383:1 A subtrait is a trait with a supertrait.

4.13:6 A supertrait is a transitive trait that a type must additionally implement.

4.13:7 A subtrait shall not be its own supertrait.

4.13:8 A trait of the form

trait T: Bound {}

4.13:9 is equivalent to a where clause of the following form:

trait T where Self: Bound {}

4.13:10 An auto trait is a trait that is implicitly and automatically implemented by a type when the types of its constituent fields implement the trait.

4.13:11 A type that has no fields implements all auto traits.

4.13:12 If determining whether a type T implements an auto trait would recursively depend on whether T implements said auto trait, this requirement is ignored and assumed to hold.

4.13:13 The following traits are auto traits:

4.13:19 No other traits are auto traits.

Examples

trait Sequence<T> {
    fn length(&self) -> u32;
    fn element_at(&self, position: u32) -> T;
}

4.13:20 Shape is a supertrait of Circle.

trait Shape {
    fn area(&self) -> f64;
}

4.13:21 Circle is a subtrait of Shape.

trait Circle: Shape {
    fn radius(&self) -> f64;
}

4.13.1. Object Safety

Legality Rules

4.13.1:1 A trait is object safe when:

4.13.1:7 An associated function is object safe when it is either an object safe dispatchable function or an object safe non-dispatchable function.

4.13.1:8 A dispatchable function is object safe when:

4.13.1:12 A function is object safe when it specifies a core::marker::Sized trait bound for Self in a type bound predicate.

4.14. Trait and Lifetime Bounds

Syntax

TypeBoundList ::=
    TypeBound (+ TypeBound)* +?

TypeBound ::=
    LifetimeIndication
  | ParenthesizedTraitBound
  | TraitBound

LifetimeIndication ::=
    Lifetime
  | '_
  | 'static

LifetimeIndicationList ::=
    LifetimeIndication (+ LifetimeIndication)* +?

ParenthesizedTraitBound ::=
    ( TraitBound )

TraitBound ::=
    ?? ForGenericParameterList? TypePath

ForGenericParameterList ::=
    for GenericParameterList

Legality Rules

4.14:1 A bound imposes a constraint on a generic parameter by limiting the set of possible generic substitutions.

4.14:2 A bound does not impose a constraint on a generic parameter of a type alias unless it is an associated item.

4.14:3 A lifetime bound is a bound that imposes a constraint on the lifetimes of generic parameters.

4.14:4 A trait bound is a bound that imposes a constraint on the traits of generic parameters.

4.14:5 A ForGenericParameterList shall not specify ConstantParameters or TypeParameters.

4.14:6 A higher-ranked trait bound is a bound that specifies an infinite list of bounds for all possible lifetimes specified by the ForGenericParameterList.

4.14:7 An opt-out trait bound is a trait bound with Punctuation ? that nullifies an implicitly added trait bound.

4.14:8 An outlives bound is a trait bound which requires that a lifetime parameter or type outlives a lifetime parameter.

4.14:9 Outlives bound 'a: 'b indicates that 'a outlives 'b.

4.14:10 Outlives bound T: 'a indicates that all lifetime parameters of T outlive 'a.

4.14:11 An implied bound is a bound that is not expressed in syntax, but is is the byproduct of relations between lifetime parameters and function parameters, between lifetime parameters and a return type, and between lifetime parameters and fields.

4.14:12 A reference of the form &'a T, where 'a is a lifetime parameter and T is a type, yields implied bound T: 'a.

4.14:13 If an outlives bound applies to the type of a field, then this bound also applies to the related abstract data type as an implied bound.

4.14:14 If an outlives bound applies to the type of a function parameter or to a return type, then this bound also applies to the related function as an implied bound.

Examples

fn draw<T: Shape>(shape: T) { ... }

4.14.1. Lifetimes

Syntax

Lifetime ::=
    ' NonKeywordIdentifier

AttributedLifetime ::=
    OuterAttributeOrDoc* Lifetime

AttributedLifetimeList ::=
    AttributedLifetime (, AttributedLifetime)* ,?

Legality Rules

4.14.1:1 A lifetime specifies the expected longevity of a value.

4.14.1:2 A lifetime bound shall apply to types and other lifetimes.

Examples

&'a i32
&'static Shape

4.14.1:3 See Paragraph 4.12. for the declaration of Shape.

4.14.2. Subtyping and Variance

Legality Rules

4.14.2:1 Subtyping is a property of types, allowing one type to be used where another type is expected.

4.14.2:2 Variance is a property of lifetime parameters and type parameters that describes the circumstances under which a generic type is a subtype of an instantiation of itself with different generic arguments.

4.14.2:3 A type is its own subtype.

4.14.2:4 F<T> is said to be

  • 4.14.2:5 Covariant over T, when T being a subtype of U implies that F<T> is a subtype of F<U>, or

  • 4.14.2:6 Contravariant over T, when T being a subtype of U implies that F<U> is a subtype of F<T>, or

  • 4.14.2:7 Invariant over T.

4.14.2:8 Variance is determined as follows:

4.14.2:9

Type

Variance in ‘a

Variance in T

4.14.2:10

&'a T

covariant

covariant

4.14.2:11

&'a mut T

covariant

invariant

4.14.2:12

*const T

covariant

4.14.2:13

*mut T

invariant

4.14.2:14

[T]

covariant

4.14.2:15

[T; N]

covariant

4.14.2:16

fn() -> T

covariant

4.14.2:17

fn(T) -> ()

contravariant

4.14.2:18

fn(T) -> T

invariant

4.14.2:19

core::call::UnsafeCell<T>

invariant

4.14.2:20

core::marker::PhantomData<T>

covariant

4.14.2:21

dyn Trait<T> + 'a

covariant

invariant

4.14.2:22 A trait is invariant in all inputs, including the Self parameter.

4.14.2:23 Lifetime parameters and type parameters are subject to variance.

4.14.2:24 The variance of a generic parameter of an abstract data type or a tuple type is determined as follows:

  1. 4.14.2:25 For each generic parameter G:

    1. 4.14.2:26 Initialize variance V of the generic parameter to any.

    2. 4.14.2:27 For each field of the abstract data type or the tuple type:

      1. 4.14.2:28 If field type T uses G, then

        1. 4.14.2:29 If V is any, set V to the variance of T over G.

        2. 4.14.2:30 Otherwise if V and the variance of T over G differ, set V to invariant.

    3. 4.14.2:31 It is a static error if variance V is any.

4.14.2:32 Expressions and statements may impose subtyping requirements on their subexpressions. Such requirements are applied after type inference, on the inferred types of the respective expressions and patterns.

4.14.2:33 It is a static error if any subtyping requirements are not met.

4.14.2:34 The subtyping requirements for statements are as follows:

4.14.2:38 The subtyping requirements for expressions are as follows:

4.14.2:46 Any type coercion resulting in a method invocation imposes the same subtyping requirements as an explicit invocation of that method would.

4.14.3. Lifetime Elision

Legality Rules

4.14.3:1 Lifetime elision is a set of rules that automatically insert lifetime parameters and/or lifetime arguments when they are elided in the source code.

4.14.3:2 A lifetime may be elided either implicitly or explicitly.

4.14.3:3 A lifetime is elided explicitly if it is the '_ lifetime.

4.14.3:4 A lifetime is elided implicitly if it is absent.

4.14.3:5 Lifetime elision rules are introduced by certain constructs and may be nested.

4.14.3:6 An elided lifetime is subject to the set of lifetime elision rules introduced by the innermost construct containing the elided lifetime.

4.14.3:7 It is a static error to elide a lifetime in a position where no lifetime elision rules are active.

4.14.3:8 Lifetimes cannot be implicitly elided within impl trait types. If no lifetime bound is present, the impl trait type is not considered to be bound by any lifetime.

4.14.3.1. Function Lifetime Elision

Legality Rules

4.14.3.1:1 Function lifetime elision is a form of lifetime elision that applies to functions, function pointer type parameters, and paths that resolve to one of the core::ops::Fn, core::ops::FnMut, and core::ops::FnOnce traits.

4.14.3.1:2 An input lifetime is one of the following lifetimes:

4.14.3.1:7 An output lifetime is one of the following lifetimes:

4.14.3.1:11 Lifetime elision proceeds as follows:

  1. 4.14.3.1:12 Each elided input lifetime is a distinct lifetime parameter in its related construct.

  2. 4.14.3.1:13 If a construct has exactly one input lifetime, then that lifetime is assigned to all elided output lifetimes.

  3. 4.14.3.1:14 If a function has a self parameter of the form &self, &mut self, or self: T where T is a type with a lifetime, then the lifetime of the self parameter is assigned to all elided output lifetimes.

  4. 4.14.3.1:15 Otherwise this is a static error.

Examples

4.14.3.1:16 Given function f of the form

fn f <'a, 'b, T: ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command;

4.14.3.1:17 its lifetime elided form is

fn f <T: ToCStr>(&mut self, args: &[T]) -> &mut Command;

4.14.3.2. Static Lifetime Elision

Legality Rules

4.14.3.2:1 Static lifetime elision is a form of lifetime elision that applies to the type ascription of constants and statics.

4.14.3.2:2 An elided lifetime of a reference type or path in the type specification of a constant or static is inferred to be the 'static' lifetime.

4.14.3.2:3 The lifetime of an associated implementation constant shall not be elided.

4.14.3.2:4 The lifetime of an associated trait constant shall not be elided.

Examples

4.14.3.2:5 Given static S of the form

static S: &[&usize] = &[];

4.14.3.2:6 its lifetime elided form is

static S: &'static [&'static usize] = &[];

4.14.3.3. Trait Object Lifetime Elision

Legality Rules

4.14.3.3:1 Trait object lifetime elision is a form of lifetime elision that applies to trait object types.

4.14.3.3:2 An elided lifetime of a trait object type is inferred as follows:

Examples

4.14.3.3:10 Given type alias T of the form

type T<'a> = &'a dyn Trait;

4.14.3.3:11 its lifetime elided form is

type T<'a> = &'a (dyn Trait + 'a);

4.14.3.4. Impl Header Lifetime Elision

Legality Rules

4.14.3.4:1 Impl header lifetime elision is a form of lifetime elision that applies to the implementing type and implemented trait (if any) of an implementation.

4.14.3.4:2 The impl header lifetime elision rules are as follows:

Examples

4.14.3.4:6 Given an implementation of the form

impl Trait<&u8, Strukt<'_>> for &i32 {}

4.14.3.4:7 its lifetime elided form is

impl<'a, 'b, 'c> Trait<&'a u8, Strukt<'b>> for &'c i32 {}

4.14.3.4:8 where 'a, 'b, and 'c are anonymous lifetime parameters that cannot be named by user-written code.