From cbc6a9dc45e158e077e23cfdb15306b6d03bce6d Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Sun, 5 Jan 2025 16:26:44 +0100 Subject: [PATCH 1/3] refactor unsizing coercion documentation The old one was quite confusing and also incorrect in a few places. --- src/type-coercions.md | 129 ++++++++++++++++++++++++++++-------------- 1 file changed, 88 insertions(+), 41 deletions(-) diff --git a/src/type-coercions.md b/src/type-coercions.md index a69b86968..6b156e956 100644 --- a/src/type-coercions.md +++ b/src/type-coercions.md @@ -134,6 +134,15 @@ r[coerce.types.ref-to-pointer] r[coerce.types.mut-to-pointer] * `&mut T` to `*mut T` +r[coerce.types.unsize] +* `T` to `U` if `T: CoerceUnsized`. For example: + ```rust + const _: &dyn std::fmt::Display = &0u8; // &u8 -> &dyn Display + const _: &[u32] = &[0, 1, 2, 3, 4, 5]; // &[u32; 4] -> &[u32] + ``` + + See [unsized coercion](#unsized-coercions) for more details. + r[coerce.types.deref] * `&T` or `&mut T` to `&U` if `T` implements `Deref`. For example: @@ -163,20 +172,6 @@ r[coerce.types.deref] r[coerce.types.deref-mut] * `&mut T` to `&mut U` if `T` implements `DerefMut`. -r[coerce.types.unsize] -* TyCtor(`T`) to TyCtor(`U`), where TyCtor(`T`) is one of - - `&T` - - `&mut T` - - `*const T` - - `*mut T` - - `Box` - - and where `U` can be obtained from `T` by [unsized coercion](#unsized-coercions). - - - r[coerce.types.fn] * Function item types to `fn` pointers @@ -190,40 +185,90 @@ r[coerce.unsize] ### Unsized Coercions r[coerce.unsize.intro] -The following coercions are called `unsized coercions`, since they -relate to converting types to unsized types, and are permitted in a few -cases where other coercions are not, as described above. They can still happen -anywhere else a coercion can occur. +The following coercions are called "unsized coercions", since their targets contain an unsized type. +unsized coercions apply to pointer-like types which point to types which can lose some of their compile-time known information (such as size or implemented traits). For example: + +```rust +use std::cell::Cell; + +fn main() { + // `&[u8; 0]` can be coerced to `&[u8]`. + // + // here `&_` is the pointer-like type, + // `[u8; 0]` is the original pointee, + // and `[u8]` is more erased pointee (it lost the length information). + let _: &[u8] = &[]; + + trait A: Super {} + impl A for () {} + + trait Super {} + impl Super for () {} + + // `&()` can be coerced to `&dyn A`, losing the type information. + let a: &dyn A = &(); + + // `&dyn A` can be coerced to `&dyn Super`, + // losing the fact that the underlying type (unit) implements `A` too. + let _: &dyn Super = a; -r[coerce.unsize.trait] -Two traits, [`Unsize`] and [`CoerceUnsized`], are used -to assist in this process and expose it for library use. The following -coercions are built-ins and, if `T` can be coerced to `U` with one of them, then -an implementation of `Unsize` for `T` will be provided: + // The same coercions work with other pointer-like types and wrappers over them: + let _: Box<[u8]> = Box::<[u8; 0]>::new([]); + let _: Cell> = Cell::new(Box::<[u8; 0]>::new([])); + + // The result of the coercion doesn't *have* to be the same pointer-like type, + // although this is only allowed for certain pairs of pointer-like types. + let _: *const dyn A = &mut (); +} +``` + +r[coerce.unsize.confusion] +> [!NOTE] +> The term "unsized" might be quite confusing, since the coercion works on sized types (pointers) and the source pointer might point to an unsized type in the first place (`&dyn A -> &dyn Super` in the example above). +> +> "unsized" refers to the main purpose of these coercions --- converting (pointers to) sized types to (pointers to) unsized types. The pointers being not the focus, since unsized types can't exist without them. + +r[coerce.unsize.metadata] +When performing unsized coercion, the pointer metadata type changes. For example, when unsized `&u32` to `&dyn Debug` metadate type changes from `()` to `DynMetadata` (note that exact metadata types are not yet stable). This can also lead to a change in the pointer size -- `&u32` is half the size of `&dyn Debug`. + +r[coerce.unsize.traits] +Three internal traits, [`Unsize`], [`CoerceUnsized`], and [`PinCoerceUnsized`] are used to assist in this process and expose it for library use. + +r[coerce.unsize.traits.unsize] +[`Unsize`] represents the fact that the target type is layout compatible with the source type and the pointer metadata of the target type can be derived from the metadata of the source, meaning that a pointer to the source type can be converted to a pointer to the target type. For example `[T; N]` implements `Unsize<[T]>` meaning that you can *unsize* former into the later, allowing coercions such as `&[T; N] -> &[T]`. + +r[coerce.unsize.traits.coerce-unsized] +[`CoerceUnsized`] represents the fact that a pointer-like type can be coerced to another pointer-like type, due to `Unsize` being implemented for their pointees. For example, `&T` implements `CoerceUnsized<&U>` when `T: Unsize`. + +r[coerce.unsize.traits.pin-coerce-unsized] +[`PinCoerceUnsized`] is an unsafe marker trait for pointer-like types unsized coercion of which does not break [`Pin`] guarantees. It is a requirement of the `CoerceUnsized` implementation for `Pin`. That is, `&D: PinCoerceUnsized` implies `Pin<&T>: CoerceUnsized>`. + +The following implementations of [`Unsize`] are built-in: r[coerce.unsize.slice] -* `[T; n]` to `[T]`. +* `[T; n]: Unsize<[T]>`. r[coerce.unsize.trait-object] -* `T` to `dyn U`, when `T` implements `U + Sized`, and `U` is [dyn compatible]. +* `T: Unsize`, when `T` implements `U + Sized`, and `U` is [dyn compatible]. r[coerce.unsize.trait-upcast] -* `dyn T` to `dyn U`, when `U` is one of `T`'s [supertraits]. - * This allows dropping auto traits, i.e. `dyn T + Auto` to `dyn U` is allowed. - * This allows adding auto traits if the principal trait has the auto trait as a super trait, i.e. given `trait T: U + Send {}`, `dyn T` to `dyn T + Send` or to `dyn U + Send` coercions are allowed. - -r[coerce.unsized.composite] -* `Foo<..., T, ...>` to `Foo<..., U, ...>`, when: - * `Foo` is a struct. - * `T` implements `Unsize`. - * The last field of `Foo` has a type involving `T`. - * If that field has type `Bar`, then `Bar` implements `Unsize>`. - * T is not part of the type of any other fields. - -r[coerce.unsized.pointer] -Additionally, a type `Foo` can implement `CoerceUnsized>` when `T` -implements `Unsize` or `CoerceUnsized>`. This allows it to provide an -unsized coercion to `Foo`. +* `dyn Trait: Unsize`, when `Super` is one of `Trait`'s [supertraits]. + * This allows dropping auto traits, i.e. `dyn Trait + Auto` to `dyn Super` is allowed. + * This allows adding auto traits if the principal trait has the auto trait as a super trait, i.e. given `trait Trait: Super + Auto {}`, `dyn Trait` to `dyn Trait + Auto` or to `dyn Super + Auto` coercions are allowed. + +r[coerce.unsize.composite] +* `S: Unsize>`, when: + * `S` is a struct. + * The type of the last field of `S` implements `Unsize` where `X` is the type of the last field of `S`. + * All generic arguments of `S` that are involved in its last field are only involved there (and not in other fields). + * All generic arguments of `S` that are not involved in its last field are unchanged between `T...` and `U...`. + +r[coerce.unsize.pointer] +A type `S` *can* implement `CoerceUnsized>` if +1. Only one field of `S` has different type than the same field of `S` (ignoring fields of type `PhantomData<_>`). +2. ... and that field's type implements `CoerceUnsized` where `X` is the type of the same field in `S`. + +This allows it to provide an unsized coercion to `S`. > [!NOTE] > While the definition of the unsized coercions and their implementation has been stabilized, the traits themselves are not yet stable and therefore can't be used directly in stable Rust. @@ -323,6 +368,8 @@ precisely. [subtype]: subtyping.md [dyn compatible]: items/traits.md#dyn-compatibility [type cast operator]: expressions/operator-expr.md#type-cast-expressions +[`Pin`]: std::pin::Pin +[`PinCoerceUnsized`]: std::pin::PinCoerceUnsized [`Unsize`]: std::marker::Unsize [`CoerceUnsized`]: std::ops::CoerceUnsized [method-call expressions]: expressions/method-call-expr.md From a2c9f869913543ef94cf5236fc59b4706da7a63b Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 12 Jun 2025 08:35:00 -0700 Subject: [PATCH 2/3] Editorial nits --- src/type-coercions.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/type-coercions.md b/src/type-coercions.md index 6b156e956..3c294c73e 100644 --- a/src/type-coercions.md +++ b/src/type-coercions.md @@ -186,7 +186,7 @@ r[coerce.unsize] r[coerce.unsize.intro] The following coercions are called "unsized coercions", since their targets contain an unsized type. -unsized coercions apply to pointer-like types which point to types which can lose some of their compile-time known information (such as size or implemented traits). For example: +Unsized coercions apply to pointer-like types which point to types which can lose some of their compile-time known information (such as size or implemented traits). For example: ```rust use std::cell::Cell; @@ -222,14 +222,13 @@ fn main() { } ``` -r[coerce.unsize.confusion] > [!NOTE] > The term "unsized" might be quite confusing, since the coercion works on sized types (pointers) and the source pointer might point to an unsized type in the first place (`&dyn A -> &dyn Super` in the example above). > > "unsized" refers to the main purpose of these coercions --- converting (pointers to) sized types to (pointers to) unsized types. The pointers being not the focus, since unsized types can't exist without them. r[coerce.unsize.metadata] -When performing unsized coercion, the pointer metadata type changes. For example, when unsized `&u32` to `&dyn Debug` metadate type changes from `()` to `DynMetadata` (note that exact metadata types are not yet stable). This can also lead to a change in the pointer size -- `&u32` is half the size of `&dyn Debug`. +When performing unsized coercion, the pointer metadata type changes. For example, when unsized `&u32` to `&dyn Debug` metadate type changes from `()` to `DynMetadata` (note that exact metadata types are not yet stable). This can also lead to a change in the pointer size --- `&u32` is half the size of `&dyn Debug`. r[coerce.unsize.traits] Three internal traits, [`Unsize`], [`CoerceUnsized`], and [`PinCoerceUnsized`] are used to assist in this process and expose it for library use. @@ -241,22 +240,23 @@ r[coerce.unsize.traits.coerce-unsized] [`CoerceUnsized`] represents the fact that a pointer-like type can be coerced to another pointer-like type, due to `Unsize` being implemented for their pointees. For example, `&T` implements `CoerceUnsized<&U>` when `T: Unsize`. r[coerce.unsize.traits.pin-coerce-unsized] -[`PinCoerceUnsized`] is an unsafe marker trait for pointer-like types unsized coercion of which does not break [`Pin`] guarantees. It is a requirement of the `CoerceUnsized` implementation for `Pin`. That is, `&D: PinCoerceUnsized` implies `Pin<&T>: CoerceUnsized>`. +[`PinCoerceUnsized`] is an unsafe marker trait for pointer-like types, unsized coercion of which does not break [`Pin`] guarantees. [`PinCoerceUnsized`] being implemented for the pointer is a requirement of the `CoerceUnsized` implementation for `Pin`. That is, `&D: PinCoerceUnsized` implies `Pin<&T>: CoerceUnsized>`. +r[coerce.unsize.built-in] The following implementations of [`Unsize`] are built-in: -r[coerce.unsize.slice] +r[coerce.unsize.built-in.slice] * `[T; n]: Unsize<[T]>`. -r[coerce.unsize.trait-object] +r[coerce.unsize.built-in.trait-object] * `T: Unsize`, when `T` implements `U + Sized`, and `U` is [dyn compatible]. -r[coerce.unsize.trait-upcast] +r[coerce.unsize.built-in.trait-upcast] * `dyn Trait: Unsize`, when `Super` is one of `Trait`'s [supertraits]. * This allows dropping auto traits, i.e. `dyn Trait + Auto` to `dyn Super` is allowed. * This allows adding auto traits if the principal trait has the auto trait as a super trait, i.e. given `trait Trait: Super + Auto {}`, `dyn Trait` to `dyn Trait + Auto` or to `dyn Super + Auto` coercions are allowed. -r[coerce.unsize.composite] +r[coerce.unsize.built-in.composite] * `S: Unsize>`, when: * `S` is a struct. * The type of the last field of `S` implements `Unsize` where `X` is the type of the last field of `S`. @@ -265,7 +265,7 @@ r[coerce.unsize.composite] r[coerce.unsize.pointer] A type `S` *can* implement `CoerceUnsized>` if -1. Only one field of `S` has different type than the same field of `S` (ignoring fields of type `PhantomData<_>`). +1. Only one field of `S` has a different type than the same field of `S` (ignoring fields of type `PhantomData<_>`). 2. ... and that field's type implements `CoerceUnsized` where `X` is the type of the same field in `S`. This allows it to provide an unsized coercion to `S`. From e2262c8dde8ebe2efbaefd975f4f6ab8aaa37b11 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 22 Jul 2025 22:35:22 +0000 Subject: [PATCH 3/3] WIP: Revise editorially Let's make some editorial revisions to clarify wording and add and clarify examples. One thing we're struggling with a bit here is how much we want to overlap with the documentation of the standard library. In some cases, we've removed detailed descriptions of the implementation rule when this is better covered in the library docs. Thanks to Eric Huss for the glossary entry added here. --- src/glossary.md | 16 ++++++ src/type-coercions.md | 118 +++++++++++++++++++++++++++++++----------- 2 files changed, 105 insertions(+), 29 deletions(-) diff --git a/src/glossary.md b/src/glossary.md index dabd65d7c..1a84692eb 100644 --- a/src/glossary.md +++ b/src/glossary.md @@ -188,6 +188,21 @@ A [*path*] is a sequence of one or more path segments used to refer to an [entity](#entity) in the current scope or other levels of a [namespace](#namespace) hierarchy. +r[glossary.pointer-metadata] +### Pointer metadata + +Pointer metadata is additional information associated with a raw pointer or reference type. + +Pointers for statically sized types (that implement the [`Sized`] trait) and `extern` types are said to be "thin" and their metadata is of type `()` (and is zero-sized). + +Pointers for [dynamically sized types] (DSTs) are said to be "wide" or "fat" and consist of the data pointer (that contains the memory address of the value) and some non-zero-sized metadata: + +* For structs whose last field is a DST, metadata is the metadata for the last field. +* For the `str` type, metadata is the length in bytes as `usize`. +* For slice types like `[T]`, metadata is the length in items as `usize`. +* For trait objects like `dyn SomeTrait`, metadata is [`DynMetadata`][DynMetadata] + (e.g. `DynMetadata`). + ### Prelude Prelude, or The Rust Prelude, is a small collection of items - mostly traits - that are @@ -290,6 +305,7 @@ uninhabited type is "empty" in the sense that there are no values of the type. T example of an uninhabited type is the [never type] `!`, or an enum with no variants `enum Never { }`. Opposite of [Inhabited](#inhabited). +[DynMetadata]: core::ptr::DynMetadata [alignment]: type-layout.md#size-and-alignment [associated item]: #associated-item [attributes]: attributes.md diff --git a/src/type-coercions.md b/src/type-coercions.md index 3c294c73e..2082594ae 100644 --- a/src/type-coercions.md +++ b/src/type-coercions.md @@ -185,8 +185,7 @@ r[coerce.unsize] ### Unsized Coercions r[coerce.unsize.intro] -The following coercions are called "unsized coercions", since their targets contain an unsized type. -Unsized coercions apply to pointer-like types which point to types which can lose some of their compile-time known information (such as size or implemented traits). For example: +The following coercions are called "unsized coercions", since their targets contain an unsized type. Unsized coercions apply to pointer-like types where some type information known about the referent at compile-time (e.g. its size or traits that it implements) can be *erased*. For example: ```rust use std::cell::Cell; @@ -194,9 +193,8 @@ use std::cell::Cell; fn main() { // `&[u8; 0]` can be coerced to `&[u8]`. // - // here `&_` is the pointer-like type, - // `[u8; 0]` is the original pointee, - // and `[u8]` is more erased pointee (it lost the length information). + // Here `&_` is the pointer-like type, `[u8; 0]` is the original + // pointee, and `[u8]` is more erased pointee (losing the length). let _: &[u8] = &[]; trait A: Super {} @@ -206,41 +204,102 @@ fn main() { impl Super for () {} // `&()` can be coerced to `&dyn A`, losing the type information. - let a: &dyn A = &(); + let _: &dyn A = &(); - // `&dyn A` can be coerced to `&dyn Super`, - // losing the fact that the underlying type (unit) implements `A` too. - let _: &dyn Super = a; + // `&dyn A` can be coerced to `&dyn Super`, losing the fact that + // the underlying type (unit) implements `A` too. + let _: &dyn Super = &() as &dyn A; - // The same coercions work with other pointer-like types and wrappers over them: + // The same coercions work with other pointer-like types and + // wrappers over them: let _: Box<[u8]> = Box::<[u8; 0]>::new([]); let _: Cell> = Cell::new(Box::<[u8; 0]>::new([])); - // The result of the coercion doesn't *have* to be the same pointer-like type, - // although this is only allowed for certain pairs of pointer-like types. + // The result of the coercion doesn't *have* to be the same + // pointer-like type, although this is only allowed for certain + // pairs of pointer-like types. let _: *const dyn A = &mut (); } ``` > [!NOTE] -> The term "unsized" might be quite confusing, since the coercion works on sized types (pointers) and the source pointer might point to an unsized type in the first place (`&dyn A -> &dyn Super` in the example above). +> The term "unsized" might be confusing, as the coercion works on sized types (the pointer-like type itself) and the source pointer might point to an unsized type in the first place (e.g. `&dyn A -> &dyn Super` in the example above). > -> "unsized" refers to the main purpose of these coercions --- converting (pointers to) sized types to (pointers to) unsized types. The pointers being not the focus, since unsized types can't exist without them. +> Here, "unsized" refers to the main purpose of these coercions, which is to produce (pointers to) unsized types. Since unsized types can't exist except behind a pointer, the pointers are deemphasized. -r[coerce.unsize.metadata] -When performing unsized coercion, the pointer metadata type changes. For example, when unsized `&u32` to `&dyn Debug` metadate type changes from `()` to `DynMetadata` (note that exact metadata types are not yet stable). This can also lead to a change in the pointer size --- `&u32` is half the size of `&dyn Debug`. +> [!NOTE] +> When doing an unsized coercion, the internal [pointer metadata] type changes. For example, when coercing `&u32` to `&dyn Debug`, the metadata type changes from `()` to `DynMetadata` (these metadata types are not yet stable, see [#81513]). This can also lead to a change in the pointer size --- `&u32` is half the size of `&dyn Debug`. r[coerce.unsize.traits] -Three internal traits, [`Unsize`], [`CoerceUnsized`], and [`PinCoerceUnsized`] are used to assist in this process and expose it for library use. +Three internal traits, [`Unsize`], [`CoerceUnsized`], and [`PinCoerceUnsized`] are used to assist in this process. r[coerce.unsize.traits.unsize] -[`Unsize`] represents the fact that the target type is layout compatible with the source type and the pointer metadata of the target type can be derived from the metadata of the source, meaning that a pointer to the source type can be converted to a pointer to the target type. For example `[T; N]` implements `Unsize<[T]>` meaning that you can *unsize* former into the later, allowing coercions such as `&[T; N] -> &[T]`. +[`Unsize`] represents that the target type is layout compatible with the source type and the [pointer metadata] of the target type can be derived from the metadata of the source. This implies that a pointer to the source type can be converted to a pointer to the target type. + +> [!EXAMPLE] +> Because `[T; N]` implements `Unsize<[T]>`, you can *unsize* `&[T; N]` into `&[T]`. r[coerce.unsize.traits.coerce-unsized] -[`CoerceUnsized`] represents the fact that a pointer-like type can be coerced to another pointer-like type, due to `Unsize` being implemented for their pointees. For example, `&T` implements `CoerceUnsized<&U>` when `T: Unsize`. +[`CoerceUnsized`] represents that a pointer-like type can be coerced to another pointer-like type when `Unsize` is implemented for the pointee of the source type. + +> [!EXAMPLE] +> `&T` implements `CoerceUnsized<&U>` when `T: Unsize`. So, since `u8: Unsize`, `&u8: CoerceUnsized<&dyn Display>`. +> +> ```rust +> # #![ feature(coerce_unsized, unsize) ] +> # use core::{fmt::Display, marker::Unsize, ops::CoerceUnsized}; +> fn f() +> where +> // These bounds are "trivial". +> u8: Unsize, +> for<'a> &'a u8: CoerceUnsized<&'a (dyn Display + 'a)>, +> { +> let _: &dyn Display = &0u8; +> } +> ``` +> +> ```rust +> # #![ feature(coerce_unsized, unsize) ] +> # use core::{marker::Unsize, ops::CoerceUnsized}; +> fn f(x: T) +> where +> T: Unsize, +> for<'a> &'a T: CoerceUnsized<&'a U>, +> { +> let _: &U = &x; +> } +> ``` r[coerce.unsize.traits.pin-coerce-unsized] -[`PinCoerceUnsized`] is an unsafe marker trait for pointer-like types, unsized coercion of which does not break [`Pin`] guarantees. [`PinCoerceUnsized`] being implemented for the pointer is a requirement of the `CoerceUnsized` implementation for `Pin`. That is, `&D: PinCoerceUnsized` implies `Pin<&T>: CoerceUnsized>`. +[`PinCoerceUnsized`] is an unsafe marker trait that is implemented for pointer-like types to indicate it is safe to perform an unsized coercion when the pointee is pinned (and must therefore uphold the [`Pin`] guarantees). + +> [!EXAMPLE] +> ```rust +> # #![ feature(coerce_unsized, pin_coerce_unsized_trait) ] +> # use core::{ops::CoerceUnsized, pin::{Pin, PinCoerceUnsized}}; +> trait Tr { fn f(); } +> impl Tr for (T, U) +> where +> // Assuming these are true... +> T: CoerceUnsized + PinCoerceUnsized, +> U: PinCoerceUnsized, +> { +> // ...we can prove this where clause: +> fn f() where Pin: CoerceUnsized> {} +> } +> ``` +> +> ```rust +> # #![ feature(coerce_unsized, pin_coerce_unsized_trait) ] +> # use core::{ops::CoerceUnsized, pin::{Pin, PinCoerceUnsized}}; +> fn f(x: Pin) +> where +> T: CoerceUnsized + PinCoerceUnsized, +> U: PinCoerceUnsized, +> { +> let _: Pin = x; +> } +> ``` r[coerce.unsize.built-in] The following implementations of [`Unsize`] are built-in: @@ -257,18 +316,17 @@ r[coerce.unsize.built-in.trait-upcast] * This allows adding auto traits if the principal trait has the auto trait as a super trait, i.e. given `trait Trait: Super + Auto {}`, `dyn Trait` to `dyn Trait + Auto` or to `dyn Super + Auto` coercions are allowed. r[coerce.unsize.built-in.composite] -* `S: Unsize>`, when: - * `S` is a struct. - * The type of the last field of `S` implements `Unsize` where `X` is the type of the last field of `S`. - * All generic arguments of `S` that are involved in its last field are only involved there (and not in other fields). - * All generic arguments of `S` that are not involved in its last field are unchanged between `T...` and `U...`. +* `S: Unsize>`, when: + * `S<..>` is a struct. + * Where `F<..>` is the type of the last field of `S<..>`, `F: Unsize>`. r[coerce.unsize.pointer] -A type `S` *can* implement `CoerceUnsized>` if -1. Only one field of `S` has a different type than the same field of `S` (ignoring fields of type `PhantomData<_>`). -2. ... and that field's type implements `CoerceUnsized` where `X` is the type of the same field in `S`. +A type `S` *can* implement `CoerceUnsized>` if both: + +* Only one field of `S` has a different type than the same field of `S` (ignoring fields of type `PhantomData<_>`). +* That field's type implements `CoerceUnsized` where `X` is the type of the corresponding field in `S`. -This allows it to provide an unsized coercion to `S`. +This allows `S` types to be coerced to `S`. > [!NOTE] > While the definition of the unsized coercions and their implementation has been stabilized, the traits themselves are not yet stable and therefore can't be used directly in stable Rust. @@ -363,10 +421,12 @@ This description is obviously informal. Making it more precise is expected to proceed as part of a general effort to specify the Rust type checker more precisely. +[#81513]: https://github.com/rust-lang/rust/issues/81513 [RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md [RFC 1558]: https://github.com/rust-lang/rfcs/blob/master/text/1558-closure-to-fn-coercion.md [subtype]: subtyping.md [dyn compatible]: items/traits.md#dyn-compatibility +[pointer metadata]: glossary.pointer-metadata [type cast operator]: expressions/operator-expr.md#type-cast-expressions [`Pin`]: std::pin::Pin [`PinCoerceUnsized`]: std::pin::PinCoerceUnsized