]> git.proxmox.com Git - rustc.git/blame - src/doc/nomicon/src/coercions.md
New upstream version 1.49.0~beta.4+dfsg1
[rustc.git] / src / doc / nomicon / src / coercions.md
CommitLineData
8bb4bdeb 1# Coercions
c1a9b12d
SL
2
3Types can implicitly be coerced to change in certain contexts. These changes are
4generally just *weakening* of types, largely focused around pointers and
5lifetimes. They mostly exist to make Rust "just work" in more cases, and are
6largely harmless.
7
8Here's all the kinds of coercion:
9
10Coercion is allowed between the following types:
11
12* Transitivity: `T_1` to `T_3` where `T_1` coerces to `T_2` and `T_2` coerces to
13 `T_3`
14* Pointer Weakening:
15 * `&mut T` to `&T`
16 * `*mut T` to `*const T`
17 * `&T` to `*const T`
18 * `&mut T` to `*mut T`
19* Unsizing: `T` to `U` if `T` implements `CoerceUnsized<U>`
32a655c1 20* Deref coercion: Expression `&x` of type `&T` to `&*x` of type `&U` if `T` derefs to `U` (i.e. `T: Deref<Target=U>`)
29967ef6
XL
21* Non-capturing closure to a function pointer ([RFC 1558], e.g. `|| 8usize` to `fn() -> usize`)
22
23[RFC 1558]: https://rust-lang.github.io/rfcs/1558-closure-to-fn-coercion.html
c1a9b12d
SL
24
25`CoerceUnsized<Pointer<U>> for Pointer<T> where T: Unsize<U>` is implemented
26for all pointer types (including smart pointers like Box and Rc). Unsize is
27only implemented automatically, and enables the following transformations:
28
e9174d1e 29* `[T; n]` => `[T]`
532ac7d7 30* `T` => `dyn Trait` where `T: Trait`
c1a9b12d
SL
31* `Foo<..., T, ...>` => `Foo<..., U, ...>` where:
32 * `T: Unsize<U>`
33 * `Foo` is a struct
32a655c1 34 * Only the last field of `Foo` has type involving `T`
c1a9b12d 35 * `T` is not part of the type of any other fields
32a655c1 36 * `Bar<T>: Unsize<Bar<U>>`, if the last field of `Foo` has type `Bar<T>`
c1a9b12d
SL
37
38Coercions occur at a *coercion site*. Any location that is explicitly typed
39will cause a coercion to its type. If inference is necessary, the coercion will
40not be performed. Exhaustively, the coercion sites for an expression `e` to
41type `U` are:
42
43* let statements, statics, and consts: `let x: U = e`
44* Arguments to functions: `takes_a_U(e)`
45* Any expression that will be returned: `fn foo() -> U { e }`
46* Struct literals: `Foo { some_u: e }`
47* Array literals: `let x: [U; 10] = [e, ..]`
48* Tuple literals: `let x: (U, ..) = (e, ..)`
49* The last expression in a block: `let x: U = { ..; e }`
50
51Note that we do not perform coercions when matching traits (except for
52receivers, see below). If there is an impl for some type `U` and `T` coerces to
53`U`, that does not constitute an implementation for `T`. For example, the
54following will not type check, even though it is OK to coerce `t` to `&T` and
55there is an impl for `&T`:
56
532ac7d7 57```rust,compile_fail
c1a9b12d
SL
58trait Trait {}
59
60fn foo<X: Trait>(t: X) {}
61
62impl<'a> Trait for &'a i32 {}
63
c1a9b12d
SL
64fn main() {
65 let t: &mut i32 = &mut 0;
66 foo(t);
67}
68```
69
70```text
0bf4aa26
XL
71error[E0277]: the trait bound `&mut i32: Trait` is not satisfied
72 --> src/main.rs:9:5
73 |
749 | foo(t);
75 | ^^^ the trait `Trait` is not implemented for `&mut i32`
76 |
77 = help: the following implementations were found:
78 <&'a i32 as Trait>
79note: required by `foo`
80 --> src/main.rs:3:1
81 |
823 | fn foo<X: Trait>(t: X) {}
83 | ^^^^^^^^^^^^^^^^^^^^^^
84
85error: aborting due to previous error
c1a9b12d 86```