about summary refs log tree commit diff
path: root/src/doc/rustc-dev-guide
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2023-11-01 20:48:58 +0000
committerMichael Goulet <michael@errs.io>2023-11-02 06:23:08 -0400
commit7ed60a6a35bd60e30a4401f7efe5eb832cbcff7d (patch)
treebcb594a51d1caa483920e983923ed90a20921a42 /src/doc/rustc-dev-guide
parent892db4457d1a236a6e0dbb0a953afe3522e5faa7 (diff)
downloadrust-7ed60a6a35bd60e30a4401f7efe5eb832cbcff7d.tar.gz
rust-7ed60a6a35bd60e30a4401f7efe5eb832cbcff7d.zip
Add some documentation for unsizing
Diffstat (limited to 'src/doc/rustc-dev-guide')
-rw-r--r--src/doc/rustc-dev-guide/src/traits/unsize.md84
1 files changed, 84 insertions, 0 deletions
diff --git a/src/doc/rustc-dev-guide/src/traits/unsize.md b/src/doc/rustc-dev-guide/src/traits/unsize.md
new file mode 100644
index 00000000000..b1176099208
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/traits/unsize.md
@@ -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`.
\ No newline at end of file