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:
- Transitivity:
T_1toT_3whereT_1coerces toT_2andT_2coerces toT_3 - Pointer Weakening:
&mut Tto&T*mut Tto*const T&Tto*const T&mut Tto*mut T
- Unsizing:
TtoUifTimplementsCoerceUnsized<U> - Deref coercion: Expression
&xof type&Tto&*xof type&UifTderefs toU(i.e.T: Deref<Target=U>) - Non-capturing closure to a function pointer (RFC 1558, e.g.
|| 8usizetofn() -> usize)
CoerceUnsized<Pointer<U>> for Pointer<T> where T: Unsize<U> 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=>dyn TraitwhereT: TraitFoo<..., T, ...>=>Foo<..., U, ...>where:T: Unsize<U>Foois a struct- Only the last field of
Foohas type involvingT Tis not part of the type of any other fieldsBar<T>: Unsize<Bar<U>>, if the last field ofFoohas typeBar<T>
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:
trait Trait {} fn foo<X: Trait>(t: X) {} impl<'a> Trait for &'a i32 {} fn main() { let t: &mut i32 = &mut 0; foo(t); }
error[E0277]: the trait bound `&mut i32: Trait` is not satisfied
--> src/main.rs:9:5
|
9 | foo(t);
| ^^^ the trait `Trait` is not implemented for `&mut i32`
|
= help: the following implementations were found:
<&'a i32 as Trait>
note: required by `foo`
--> src/main.rs:3:1
|
3 | fn foo<X: Trait>(t: X) {}
| ^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error