-
Notifications
You must be signed in to change notification settings - Fork 533
Refactor unsizing coercion documentation #1731
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Refactor unsizing coercion documentation #1731
Conversation
6f8650a
to
08bec64
Compare
This comment has been minimized.
This comment has been minimized.
@rust-lang/types would you be able to review this? |
To add a bit more color, it'd be good to get a double check that the content is factually accurate before spec team takes it on for editorial review. |
src/type-coercions.md
Outdated
<!-- FIXME: are there more requirements for `CoerceUnsized`? --> | ||
|
||
r[coerce.unsize.coerce-unsized-impls] | ||
Types which currently implement `CoerceUnsized<_>` (assuming `T: Unsize<U>`, `'a: 'b`, `A: CoerceUnsized<B>`, `Al: Allocator`): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally I would prefer to not duplicate the list of impls from the standard library here. I assume the user can click the link to CoerceUnsized
to see which impls it has?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, mh. Yes, users can find them in the std docs (that's where I got the impls from!).
However, if we want the reference to be prescriptive, I think we should include this. While this is library code, it controls how a language feature behaves.
But I don't have a strong opinion here, if you think that this is not useful I can remove the list.
08bec64
to
9271fdd
Compare
@WaffleLapkin To move this along, would it be possible to split this PR up a little so it doesn't get hung up? In particular, I think it would move things faster if we remove the name change (unsized -> unsizing) to avoid getting stuck on bikeshedding (that doesn't mean we can't make that change separately, it just adds friction). And remove the list of You can either just make this PR smaller, or open a new smaller PR, whichever is more convenient. Assigning TC since he asked. |
b68840f
to
56ee0bb
Compare
I can review this over the weekend |
56ee0bb
to
2a242c5
Compare
2a242c5
to
7780344
Compare
@ehuss I forgot to comment, but I removed the impls and split off the rename. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems good to me in terms of correctness.
When performing unsized coercion, the pointer metadata type changes. For example, when unsized `&u32` to `&dyn Debug` metadate type changes from `()` to `DynMetadata<dyn Debug>` (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 traits, [`Unsize`], [`CoerceUnsized`], and [`PinCoerceUnsized`] are used to assist in this process and expose it for library use. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may be worth clarifying these traits are unstable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a note about this down on line 273.
This is actually an interesting case. Generally in the Reference we don't document the unstable, just the exposed stable behaviors. But here, it's probably indeed easiest to describe those stable behaviors in terms of the unstable traits, and we'd already made this exception.
src/type-coercions.md
Outdated
Additionally, a type `Foo<T>` can implement `CoerceUnsized<Foo<U>>` when `T` | ||
implements `Unsize<U>` or `CoerceUnsized<Foo<U>>`. This allows it to provide an | ||
unsized coercion to `Foo<U>`. | ||
<!-- FIXME: are there more requirements for `CoerceUnsized`? --> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, I think another constraint here is that only one field can be coerced.
The old one was quite confusing and also incorrect in a few places.
7780344
to
cddb6e7
Compare
Is there anything I can do to move this forward? |
let _: Cell<Box<[u8]>> = Cell::new(Box::<[u8; 0]>::new([])); | ||
|
||
// The result of the coercion doesn't *have* to be the same pointer-like type, | ||
// alhtough this is only allowed for certain pairs of pointer-like types. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// alhtough this is only allowed for certain pairs of pointer-like types. | |
// although this is only allowed for certain pairs of pointer-like types. |
When performing unsized coercion, the pointer metadata type changes. For example, when unsized `&u32` to `&dyn Debug` metadate type changes from `()` to `DynMetadata<dyn Debug>` (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 traits, [`Unsize`], [`CoerceUnsized`], and [`PinCoerceUnsized`] are used to assist in this process and expose it for library use. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Three 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 and expose it for library use. |
* The last field is the *only* field which type involves `T`. | ||
* The type of the last field implements `Unsize<F>` where `F` is the same type with `T` replaced by `U`. i.e. if the field has type `Bar<T>`, then `Bar<T>` implements `Unsize<Bar<U>>`. | ||
|
||
r[coerce.unsize.pointer] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
r[coerce.unsize.pointer] | |
r[coerce.unsize.struct] |
🤔
* `dyn T: Unsize<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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
existing, but pls change this to use TrA and
TrBor
Fooand
Baror
Traitand
Super`
I personally tend to get very confused by single letter trait names, esp if we've just used T
to mean "any type" 2 lines above
* The type of the last field implements `Unsize<F>` where `F` is the same type with `T` replaced by `U`. i.e. if the field has type `Bar<T>`, then `Bar<T>` implements `Unsize<Bar<U>>`. | ||
|
||
r[coerce.unsize.pointer] | ||
A type `S<..., T, ...>` can implement `CoerceUnsized<S<..., U, ...>>` if |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unsizing can change an arbitrary number of struct type/const args as long all of them are only mentioned in the last field and that last field impls CoerceUnsized
The last field of
S
has a type involvingT
. i.e. it's either ofT
orC<..., T, ...>
whereC
is a type constructor andT
is only present in it once (C<T, T>
is disallowed).
Where do you get the "T
is only present once" requirement from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wait, confused by the difference between coerce.unsize.composite
and coerce.unsize.pointer
🤔 using
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
an example which disagrees with the current docs
trait Trait<T, U> {
type Assoc: ?Sized;
}
impl<T> Trait<T, u32> for T {
type Assoc = [u8; 4];
}
impl<T> Trait<T, u16> for T {
type Assoc = [u8];
}
struct Foo<T: Trait<T, U>, U>(<T as Trait<T, U>>::Assoc);
fn main() {
let x: &Foo<(), u32> = &Foo([0; 4]);
let y: &Foo<String, u16> = x;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nits, then r=me from the "accuracy end". Unsure whether I've got the right to merge reference PRs myself
The old one was quite confusing and also incorrect in a few places. Follow-up to #1622.