Type coercions
Coercions are defined in RFC 401. RFC 1558 then expanded on that. A coercion is implicit and has no syntax.
Coercion sites
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:
-
letstatements where an explicit type is given.For example,
42is coerced to have typei8in the following:#![allow(unused_variables)] fn main() { let _: i8 = 42; } -
staticandconststatements (similar toletstatements). -
Arguments for function calls
The value being coerced is the actual parameter, and it is coerced to the type of the formal parameter.
For example,
42is coerced to have typei8in the following:fn bar(_: i8) { } fn main() { bar(42); }For method calls, the receiver (
selfparameter) can only take advantage of unsized coercions. -
Instantiations of struct or variant fields
For example,
42is coerced to have typei8in the following:struct Foo { x: i8 } fn main() { Foo { x: 42 }; } -
Function results, either the final line of a block if it is not semicolon-terminated or any expression in a
returnstatementFor example,
42is coerced to have typei8in the following:#![allow(unused_variables)] fn main() { fn foo() -> i8 { 42 } }
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:
-
Array literals, where the array has type
[U; n]. Each sub-expression in the array literal is a coercion site for coercion to typeU. -
Array literals with repeating syntax, where the array has type
[U; n]. The repeated sub-expression is a coercion site for coercion to typeU. -
Tuples, where a tuple is a coercion site to type
(U_0, U_1, ..., U_n). Each sub-expression is a coercion site to the respective type, e.g. the zeroth sub-expression is a coercion site to typeU_0. -
Parenthesized sub-expressions (
(e)): if the expression has typeU, then the sub-expression is a coercion site toU. -
Blocks: if a block has type
U, then the last expression in the block (if it is not semicolon-terminated) is a coercion site toU. This includes blocks which are part of control flow statements, such asif/else, if the block has a known type.
Coercion types
Coercion is allowed between the following types:
-
TtoUifTis a subtype ofU(reflexive case) -
T_1toT_3whereT_1coerces toT_2andT_2coerces toT_3(transitive case)Note that this is not fully supported yet.
-
&mut Tto&T -
*mut Tto*const T -
&Tto*const T -
&mut Tto*mut T -
&Tor&mut Tto&UifTimplementsDeref<Target = U>. For example:use std::ops::Deref; struct CharContainer { value: char, } impl Deref for CharContainer { type Target = char; fn deref<'a>(&'a self) -> &'a char { &self.value } } fn foo(arg: &char) {} fn main() { let x = &mut CharContainer { value: 'y' }; foo(x); //&mut CharContainer is coerced to &char. } -
&mut Tto&mut UifTimplementsDerefMut<Target = U>. -
TyCtor(
T) to TyCtor(U), where TyCtor(T) is one of&T&mut T*const T*mut TBox<T>
and where
Ucan be obtained fromTby unsized coercion. -
Non capturing closures to
fnpointers -
!to anyT
Unsized Coercions
The following coercions are called unsized coercions, since they
relate to converting sized 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.
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:
-
[T; n]to[T]. -
TtoU, whenUis a trait object type and eitherTimplementsUorTis a trait object for a subtrait ofU. -
Foo<..., T, ...>toFoo<..., U, ...>, when:Foois a struct.TimplementsUnsize<U>.- The last field of
Foohas a type involvingT. - If that field has type
Bar<T>, thenBar<T>implementsUnsized<Bar<U>>. - T is not part of the type of any other fields.
Additionally, a type Foo<T> can implement CoerceUnsized<Foo<U>> when T
implements Unsize<U> or CoerceUnsized<Foo<U>>. This allows it to provide a
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.