]>
Commit | Line | Data |
---|---|---|
8bb4bdeb | 1 | # Coercions |
c1a9b12d SL |
2 | |
3 | Types can implicitly be coerced to change in certain contexts. These changes are | |
4 | generally just *weakening* of types, largely focused around pointers and | |
5 | lifetimes. They mostly exist to make Rust "just work" in more cases, and are | |
6 | largely harmless. | |
7 | ||
8 | Here's all the kinds of coercion: | |
9 | ||
10 | Coercion 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 | |
26 | for all pointer types (including smart pointers like Box and Rc). Unsize is | |
27 | only 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 | |
38 | Coercions occur at a *coercion site*. Any location that is explicitly typed | |
39 | will cause a coercion to its type. If inference is necessary, the coercion will | |
40 | not be performed. Exhaustively, the coercion sites for an expression `e` to | |
41 | type `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 | ||
51 | Note that we do not perform coercions when matching traits (except for | |
52 | receivers, 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 | |
54 | following will not type check, even though it is OK to coerce `t` to `&T` and | |
55 | there is an impl for `&T`: | |
56 | ||
532ac7d7 | 57 | ```rust,compile_fail |
c1a9b12d SL |
58 | trait Trait {} |
59 | ||
60 | fn foo<X: Trait>(t: X) {} | |
61 | ||
62 | impl<'a> Trait for &'a i32 {} | |
63 | ||
c1a9b12d SL |
64 | fn main() { |
65 | let t: &mut i32 = &mut 0; | |
66 | foo(t); | |
67 | } | |
68 | ``` | |
69 | ||
70 | ```text | |
0bf4aa26 XL |
71 | error[E0277]: the trait bound `&mut i32: Trait` is not satisfied |
72 | --> src/main.rs:9:5 | |
73 | | | |
74 | 9 | 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> | |
79 | note: required by `foo` | |
80 | --> src/main.rs:3:1 | |
81 | | | |
82 | 3 | fn foo<X: Trait>(t: X) {} | |
83 | | ^^^^^^^^^^^^^^^^^^^^^^ | |
84 | ||
85 | error: aborting due to previous error | |
c1a9b12d | 86 | ``` |