r[coerce]

Type coercions

r[coerce.intro] Type coercions are implicit operations that change the type of a value. They happen automatically at specific locations and are highly restricted in what types actually coerce.

r[coerce.as] Any conversions allowed by coercion can also be explicitly performed by the type cast operator, as.

Coercions are originally defined in RFC 401 and expanded upon in RFC 1558.

r[coerce.site]

Coercion sites

r[coerce.site.intro] A coercion can only occur at certain coercion sites in a program; these are typically places where the desired type is explicit or can be derived by propagation from explicit types (without type inference). Possible coercion sites are:

r[coerce.site.let]

r[coerce.site.value]

r[coerce.site.argument]

r[coerce.site.constructor]

r[coerce.site.return]

r[coerce.site.subexpr] If the expression in one of these coercion sites is a coercion-propagating expression, then the relevant sub-expressions in that expression are also coercion sites. Propagation recurses from these new coercion sites. Propagating expressions and their relevant sub-expressions are:

r[coerce.site.array]

r[coerce.site.repeat]

r[coerce.site.tuple]

r[coerce.site.parenthesis]

r[coerce.site.block]

r[coerce.types]

Coercion types

r[coerce.types.intro] Coercion is allowed between the following types:

r[coerce.types.reflexive]

r[coerce.types.transitive]

r[coerce.types.mut-reborrow]

r[coerce.types.mut-pointer]

r[coerce.types.ref-to-pointer]

r[coerce.types.mut-to-pointer]

r[coerce.types.deref]

r[coerce.types.deref-mut]

r[coerce.types.unsize]

r[coerce.types.fn]

r[coerce.types.closure]

r[coerce.types.never]

r[coerce.unsize]

Unsized Coercions

r[coerce.unsize.intro] The following coercions are called unsized coercions, since they relate to converting types to unsized types, and are permitted in a few cases where other coercions are not, as described above. They can still happen anywhere else a coercion can occur.

r[coerce.unsize.trait] Two traits, Unsize and CoerceUnsized, are used to assist in this process and expose it for library use. The following coercions are built-ins and, if T can be coerced to U with one of them, then an implementation of Unsize<U> for T will be provided:

r[coerce.unsize.slice]

r[coerce.unsize.trait-object]

r[coerce.unsize.trait-upcast]

r[coerce.unsized.composite]

r[coerce.unsized.pointer] Additionally, a type Foo<T> can implement CoerceUnsized<Foo<U>> when T implements Unsize<U> or CoerceUnsized<Foo<U>>. This allows it to provide an unsized coercion to Foo<U>.

[!NOTE] While the definition of the unsized coercions and their implementation has been stabilized, the traits themselves are not yet stable and therefore can't be used directly in stable Rust.

r[coerce.least-upper-bound]

Least upper bound coercions

r[coerce.least-upper-bound.intro] In some contexts, the compiler must coerce together multiple types to try and find the most general type. This is called a "Least Upper Bound" coercion. LUB coercion is used and only used in the following situations:

r[coerce.least-upper-bound.target] In each such case, there are a set of types T0..Tn to be mutually coerced to some target type T_t, which is unknown to start.

r[coerce.least-upper-bound.computation] Computing the LUB coercion is done iteratively. The target type T_t begins as the type T0. For each new type Ti, we consider whether

r[coerce.least-upper-bound.computation-identity]

r[coerce.least-upper-bound.computation-replace]

r[coerce.least-upper-bound.computation-unify]

Examples:

# let (a, b, c) = (0, 1, 2);
// For if branches
let bar = if true {
    a
} else if false {
    b
} else {
    c
};

// For match arms
let baw = match 42 {
    0 => a,
    1 => b,
    _ => c,
};

// For array elements
let bax = [a, b, c];

// For closure with multiple return statements
let clo = || {
    if true {
        a
    } else if false {
        b
    } else {
        c
    }
};
let baz = clo();

// For type checking of function with multiple return statements
fn foo() -> i32 {
    let (a, b, c) = (0, 1, 2);
    match 42 {
        0 => a,
        1 => b,
        _ => c,
    }
}

In these examples, types of the ba* are found by LUB coercion. And the compiler checks whether LUB coercion result of a, b, c is i32 in the processing of the function foo.

Caveat

This description is obviously informal. Making it more precise is expected to proceed as part of a general effort to specify the Rust type checker more precisely.