% Coercions Types can implicitly be coerced to change in certain contexts. These changes are generally just *weakening* of types, largely focused around pointers and lifetimes. They mostly exist to make Rust "just work" in more cases, and are largely harmless. Here's all the kinds of coercion: Coercion is allowed between the following types: * Subtyping: `T` to `U` if `T` is a [subtype](lifetimes.html#subtyping-and-variance) of `U` * Transitivity: `T_1` to `T_3` where `T_1` coerces to `T_2` and `T_2` coerces to `T_3` * Pointer Weakening: * `&mut T` to `&T` * `*mut T` to `*const T` * `&T` to `*const T` * `&mut T` to `*mut T` * Unsizing: `T` to `U` if `T` implements `CoerceUnsized` `CoerceUnsized> for Pointer where T: Unsize` is implemented for all pointer types (including smart pointers like Box and Rc). Unsize is only implemented automatically, and enables the following transformations: * `[T, ..n]` => `[T]` * `T` => `Trait` where `T: Trait` * `SubTrait` => `Trait` where `SubTrait: Trait` (TODO: is this now implied by the previous?) * `Foo<..., T, ...>` => `Foo<..., U, ...>` where: * `T: Unsize` * `Foo` is a struct * Only the last field has type `T` * `T` is not part of the type of any other fields Coercions occur at a *coercion site*. Any location that is explicitly typed will cause a coercion to its type. If inference is necessary, the coercion will not be performed. Exhaustively, the coercion sites for an expression `e` to type `U` are: * let statements, statics, and consts: `let x: U = e` * Arguments to functions: `takes_a_U(e)` * Any expression that will be returned: `fn foo() -> U { e }` * Struct literals: `Foo { some_u: e }` * Array literals: `let x: [U; 10] = [e, ..]` * Tuple literals: `let x: (U, ..) = (e, ..)` * The last expression in a block: `let x: U = { ..; e }` Note that we do not perform coercions when matching traits (except for receivers, see below). If there is an impl for some type `U` and `T` coerces to `U`, that does not constitute an implementation for `T`. For example, the following will not type check, even though it is OK to coerce `t` to `&T` and there is an impl for `&T`: ```rust trait Trait {} fn foo(t: X) {} impl<'a> Trait for &'a i32 {} fn main() { let t: &mut i32 = &mut 0; foo(t); } ``` ```text :10:5: 10:8 error: the trait `Trait` is not implemented for the type `&mut i32` [E0277] :10 foo(t); ^~~ ```