Add some documentation for unsizing
This commit is contained in:
parent
a79c64e683
commit
1f674ff57b
|
|
@ -0,0 +1,84 @@
|
|||
# [`CoerceUnsized`](https://doc.rust-lang.org/std/ops/trait.CoerceUnsized.html)
|
||||
|
||||
`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 `CoerceUnsized` include:
|
||||
* `&T`
|
||||
* `Arc<T>`
|
||||
* `Box<T>`
|
||||
|
||||
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.
|
||||
|
||||
# [`Unsize`](https://doc.rust-lang.org/std/marker/trait.Unsize.html)
|
||||
|
||||
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.
|
||||
|
||||
## Primitive unsizing implementations
|
||||
|
||||
Built-in implementations are provided for:
|
||||
* `T` -> `dyn Trait + 'a` when `T: Trait` (and `T: Sized + 'a`, and `Trait`
|
||||
is object safe).
|
||||
* `[T; N]` -> `[T]`
|
||||
|
||||
## Structural implementations
|
||||
|
||||
There are two implementations of `Unsize` which can be thought of as
|
||||
structural:
|
||||
* `(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
|
||||
[`unsized_tuple_coercion`] feature.
|
||||
* `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
|
||||
`Pi`, .., `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.
|
||||
|
||||
[`unsized_tuple_coercion`]: https://doc.rust-lang.org/beta/unstable-book/language-features/unsized-tuple-coercion.html
|
||||
|
||||
## Upcasting implementations
|
||||
|
||||
Two things are called "upcasting" internally:
|
||||
1. True upcasting `dyn SubTrait` -> `dyn SuperTrait` (this also allows
|
||||
dropping auto traits and adjusting lifetimes, as below).
|
||||
2. Dropping auto traits and adjusting the lifetimes of dyn trait
|
||||
*without changing the principal[^1]*:
|
||||
`dyn Trait + AutoTraits... + 'a` -> `dyn Trait + NewAutoTraits... + 'b`
|
||||
when `AutoTraits` ⊇ `NewAutoTraits`, and `'a: 'b`.
|
||||
|
||||
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](https://github.com/rust-lang/rust/pull/114036) to
|
||||
support the complexities of associated types.
|
||||
|
||||
Specifically, the upcasting algorithm involves: For each supertrait of the
|
||||
source dyn trait's principal (including itself)...
|
||||
1. 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]).
|
||||
2. 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).
|
||||
3. 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>`).
|
||||
|
||||
[via an impl]: https://github.com/rust-lang/rust/blob/f3457dbf84cd86d284454d12705861398ece76c3/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl.rs#L19
|
||||
|
||||
Specifically, (3.) prevents a choice of projection bound to guide inference
|
||||
unnecessarily, though it may guide inference when it is unambiguous.
|
||||
|
||||
[^1]: The principal is the one non-auto trait of a `dyn Trait`.
|
||||
Loading…
Reference in New Issue