CoerceUnsized is primarily concerned with data containers. When a struct
(typically, a smart pointer) implements
CoerceUnsized, that means that the
data it points to is being unsized.
Some implementors of
This trait is (eventually) intended to be implemented by user-written smart
pointers, and there are rules about when a type is allowed to implement
CoerceUnsized that are explained in the trait's documentation.
To contrast, the
Unsize trait is concerned the actual types that are allowed
to be unsized.
This is not intended to be implemented by users ever, since
Unsize does not
instruct the compiler (namely codegen) how to unsize a type, just whether it
is allowed to be unsized. This is paired somewhat intimately with codegen
which must understand how types are represented and unsized.
Built-in implementations are provided for:
dyn Trait + 'awhen
T: Sized + 'a, and
Traitis object safe).
There are two implementations of
Unsize which can be thought of as
(A1, A2, .., An): Unsize<(A1, A2, .., U)>given
An: Unsize<U>, which allows the tail field of a tuple to be unsized. This is gated behind the
Struct<.., Pi, .., Pj, ..>: Unsize<Struct<.., Ui, .., Uj, ..>>given
TailField<Pi, .., Pj>: Unsize<Ui, .. Uj>, which allows the tail field of a struct to be unsized if it is the only field that mentions generic parameters
Pj(which don't need to be contiguous).
The rules for the latter implementation are slightly complicated, since they may allow more than one parameter to be changed (not necessarily unsized) and are best stated in terms of the tail field of the struct.
Two things are called "upcasting" internally:
- True upcasting
dyn SuperTrait(this also allows dropping auto traits and adjusting lifetimes, as below).
- Dropping auto traits and adjusting the lifetimes of dyn trait
without changing the principal1:
dyn Trait + AutoTraits... + 'a->
dyn Trait + NewAutoTraits... + 'bwhen
These may seem like different operations, since (1.) includes adjusting the vtable of a dyn trait, while (2.) is a no-op. However, to the type system, these are handled with much the same code.
This built-in implementation of
Unsize is the most involved, particularly
after it was reworked to
support the complexities of associated types.
Specifically, the upcasting algorithm involves: For each supertrait of the source dyn trait's principal (including itself)...
- Unify the super trait ref with the principal of the target (making sure we only ever upcast to a true supertrait, and never via an impl).
- For every auto trait in the source, check that it's present in the principal (allowing us to drop auto traits, but never gain new ones).
- For every projection in the source, check that it unifies with a single
projection in the target (since there may be more than one given
trait Sub: Sup<.., A = i32> + Sup<.., A = u32>).
Specifically, (3.) prevents a choice of projection bound to guide inference unnecessarily, though it may guide inference when it is unambiguous.
The principal is the one non-auto trait of a