|
| 1 | +# [`CoerceUnsized`](https://doc.rust-lang.org/std/ops/trait.CoerceUnsized.html) |
| 2 | + |
| 3 | +`CoerceUnsized` is primarily concerned with data containers. When a struct |
| 4 | +(typically, a smart pointer) implements `CoerceUnsized`, that means that the |
| 5 | +data it points to is being unsized. |
| 6 | + |
| 7 | +Some implementors of `CoerceUnsized` include: |
| 8 | +* `&T` |
| 9 | +* `Arc<T>` |
| 10 | +* `Box<T>` |
| 11 | + |
| 12 | +This trait is (eventually) intended to be implemented by user-written smart |
| 13 | +pointers, and there are rules about when a type is allowed to implement |
| 14 | +`CoerceUnsized` that are explained in the trait's documentation. |
| 15 | + |
| 16 | +# [`Unsize`](https://doc.rust-lang.org/std/marker/trait.Unsize.html) |
| 17 | + |
| 18 | +To contrast, the `Unsize` trait is concerned the actual types that are allowed |
| 19 | +to be unsized. |
| 20 | + |
| 21 | +This is not intended to be implemented by users ever, since `Unsize` does not |
| 22 | +instruct the compiler (namely codegen) *how* to unsize a type, just whether it |
| 23 | +is allowed to be unsized. This is paired somewhat intimately with codegen |
| 24 | +which must understand how types are represented and unsized. |
| 25 | + |
| 26 | +## Primitive unsizing implementations |
| 27 | + |
| 28 | +Built-in implementations are provided for: |
| 29 | +* `T` -> `dyn Trait + 'a` when `T: Trait` (and `T: Sized + 'a`, and `Trait` |
| 30 | + is object safe). |
| 31 | +* `[T; N]` -> `[T]` |
| 32 | + |
| 33 | +## Structural implementations |
| 34 | + |
| 35 | +There are two implementations of `Unsize` which can be thought of as |
| 36 | +structural: |
| 37 | +* `(A1, A2, .., An): Unsize<(A1, A2, .., U)>` given `An: Unsize<U>`, which |
| 38 | + allows the tail field of a tuple to be unsized. This is gated behind the |
| 39 | + [`unsized_tuple_coercion`] feature. |
| 40 | +* `Struct<.., Pi, .., Pj, ..>: Unsize<Struct<.., Ui, .., Uj, ..>>` given |
| 41 | + `TailField<Pi, .., Pj>: Unsize<Ui, .. Uj>`, which allows the tail field of a |
| 42 | + struct to be unsized if it is the only field that mentions generic parameters |
| 43 | + `Pi`, .., `Pj` (which don't need to be contiguous). |
| 44 | + |
| 45 | +The rules for the latter implementation are slightly complicated, since they |
| 46 | +may allow more than one parameter to be changed (not necessarily unsized) and |
| 47 | +are best stated in terms of the tail field of the struct. |
| 48 | + |
| 49 | +[`unsized_tuple_coercion`]: https://doc.rust-lang.org/beta/unstable-book/language-features/unsized-tuple-coercion.html |
| 50 | + |
| 51 | +## Upcasting implementations |
| 52 | + |
| 53 | +Two things are called "upcasting" internally: |
| 54 | +1. True upcasting `dyn SubTrait` -> `dyn SuperTrait` (this also allows |
| 55 | + dropping auto traits and adjusting lifetimes, as below). |
| 56 | +2. Dropping auto traits and adjusting the lifetimes of dyn trait |
| 57 | + *without changing the principal[^1]*: |
| 58 | + `dyn Trait + AutoTraits... + 'a` -> `dyn Trait + NewAutoTraits... + 'b` |
| 59 | + when `AutoTraits` ⊇ `NewAutoTraits`, and `'a: 'b`. |
| 60 | + |
| 61 | +These may seem like different operations, since (1.) includes adjusting the |
| 62 | +vtable of a dyn trait, while (2.) is a no-op. However, to the type system, |
| 63 | +these are handled with much the same code. |
| 64 | + |
| 65 | +This built-in implementation of `Unsize` is the most involved, particularly |
| 66 | +after [it was reworked](https://github.com/rust-lang/rust/pull/114036) to |
| 67 | +support the complexities of associated types. |
| 68 | + |
| 69 | +Specifically, the upcasting algorithm involves: For each supertrait of the |
| 70 | +source dyn trait's principal (including itself)... |
| 71 | +1. Unify the super trait ref with the principal of the target (making sure |
| 72 | + we only ever upcast to a true supertrait, and never [via an impl]). |
| 73 | +2. For every auto trait in the source, check that it's present in the principal |
| 74 | + (allowing us to drop auto traits, but never gain new ones). |
| 75 | +3. For every projection in the source, check that it unifies with a single |
| 76 | + projection in the target (since there may be more than one given |
| 77 | + `trait Sub: Sup<.., A = i32> + Sup<.., A = u32>`). |
| 78 | + |
| 79 | +[via an impl]: https://github.com/rust-lang/rust/blob/f3457dbf84cd86d284454d12705861398ece76c3/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs#L19 |
| 80 | + |
| 81 | +Specifically, (3.) prevents a choice of projection bound to guide inference |
| 82 | +unnecessarily, though it may guide inference when it is unambiguous. |
| 83 | + |
| 84 | +[^1]: The principal is the one non-auto trait of a `dyn Trait`. |
0 commit comments