about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2023-11-02 15:31:21 +0100
committerGitHub <noreply@github.com>2023-11-02 15:31:21 +0100
commit957562583538aa4934957121fef155cbf7324d56 (patch)
tree7a420e8318d5fe21441796feba4f0f3eedffbd1e
parent298edd6d463c4c4f32cff3e6a18fd569854ba5c5 (diff)
parent1221b7b652a9859340fad0cd6db78c7493f3847f (diff)
downloadrust-957562583538aa4934957121fef155cbf7324d56.tar.gz
rust-957562583538aa4934957121fef155cbf7324d56.zip
Rollup merge of #117495 - compiler-errors:unsize-docs, r=lcnr
Clarify `Unsize` documentation

The documentation erroneously says that:

```rust
/// - Types implementing a trait `Trait` also implement `Unsize<dyn Trait>`.
/// - Structs `Foo<..., T, ...>` implement `Unsize<Foo<..., U, ...>>` if all of these conditions
///   are met:
///   - `T: Unsize<U>`.
///   - Only the last field of `Foo` has a type involving `T`.
///   - `Bar<T>: Unsize<Bar<U>>`, where `Bar<T>` stands for the actual type of that last field.
```

Specifically, `T: Unsize<U>` is not required to hold -- only the final field must implement `FinalField<T>: Unsize<FinalField<U>>`. This can be demonstrated by the test I added.

---

Second commit fleshes out the documentation a lot more.
-rw-r--r--library/core/src/marker.rs18
-rw-r--r--tests/ui/unsized/unsize-coerce-multiple-adt-params.rs29
2 files changed, 41 insertions, 6 deletions
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index d396a707b55..13437d8f961 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -155,12 +155,18 @@ pub trait Sized {
 /// Those implementations are:
 ///
 /// - Arrays `[T; N]` implement `Unsize<[T]>`.
-/// - Types implementing a trait `Trait` also implement `Unsize<dyn Trait>`.
-/// - Structs `Foo<..., T, ...>` implement `Unsize<Foo<..., U, ...>>` if all of these conditions
-///   are met:
-///   - `T: Unsize<U>`.
-///   - Only the last field of `Foo` has a type involving `T`.
-///   - `Bar<T>: Unsize<Bar<U>>`, where `Bar<T>` stands for the actual type of that last field.
+/// - A type implements `Unsize<dyn Trait + 'a>` if all of these conditions are met:
+///   - The type implements `Trait`.
+///   - `Trait` is object safe.
+///   - The type is sized.
+///   - The type outlives `'a`.
+/// - Structs `Foo<..., T1, ..., Tn, ...>` implement `Unsize<Foo<..., U1, ..., Un, ...>>`
+/// where any number of (type and const) parameters may be changed if all of these conditions
+/// are met:
+///   - Only the last field of `Foo` has a type involving the parameters `T1`, ..., `Tn`.
+///   - All other parameters of the struct are equal.
+///   - `Field<T1, ..., Tn>: Unsize<Field<U1, ..., Un>>`, where `Field<...>` stands for the actual
+///     type of the struct's last field.
 ///
 /// `Unsize` is used along with [`ops::CoerceUnsized`] to allow
 /// "user-defined" containers such as [`Rc`] to contain dynamically-sized
diff --git a/tests/ui/unsized/unsize-coerce-multiple-adt-params.rs b/tests/ui/unsized/unsize-coerce-multiple-adt-params.rs
new file mode 100644
index 00000000000..eba341ff284
--- /dev/null
+++ b/tests/ui/unsized/unsize-coerce-multiple-adt-params.rs
@@ -0,0 +1,29 @@
+// check-pass
+
+struct Foo<T, U>
+where
+    (T, U): Trait,
+{
+    f: <(T, U) as Trait>::Assoc,
+}
+
+trait Trait {
+    type Assoc: ?Sized;
+}
+
+struct Count<const N: usize>;
+
+impl<const N: usize> Trait for (i32, Count<N>) {
+    type Assoc = [(); N];
+}
+
+impl<'a> Trait for (u32, ()) {
+    type Assoc = [()];
+}
+
+// Test that we can unsize several trait params in creative ways.
+fn unsize<const N: usize>(x: &Foo<i32, Count<N>>) -> &Foo<u32, ()> {
+    x
+}
+
+fn main() {}