Skip to content
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

Tracking issue for DST coercions (coerce_unsized, unsize) stabilization #27732

Closed
aturon opened this issue Aug 12, 2015 · 45 comments
Closed

Tracking issue for DST coercions (coerce_unsized, unsize) stabilization #27732

aturon opened this issue Aug 12, 2015 · 45 comments
Labels
A-coercions Area: implicit and explicit `expr as Type` coercions A-DSTs Area: Dynamically-sized types (DSTs) B-RFC-implemented Blocker: Approved by a merged RFC and implemented. B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC Libs-Tracked Libs issues that are tracked on the team's project board. S-tracking-needs-summary Status: It's hard to tell what's been done and what hasn't! Someone should do some investigation. T-lang Relevant to the language team, which will review and decide on the PR/issue. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@aturon
Copy link
Member

aturon commented Aug 12, 2015

DST coercions were the last part of DST to land, and are still undergoing some changes.

Before stabilization, at the very least the API surface here needs some scrutiny from the libs team for naming and other conventions issues.

cc @nrc @gankro

Things to consider prior to stabilization

@aturon aturon added T-lang Relevant to the language team, which will review and decide on the PR/issue. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. B-unstable Blocker: Implemented in the nightly compiler and unstable. labels Aug 12, 2015
@aturon
Copy link
Member Author

aturon commented Sep 23, 2015

@nrc, what's your sense of the status for these features? Do you feel ready to stabilize after the libs team takes a look?

@nrc
Copy link
Member

nrc commented Sep 23, 2015

My feeling (and it is really just a feeling, I have no data to back this up) is that DST coercions haven't yet got the use they need to prove themselves for stabilisation. I'd love to be wrong about this - if someone could show me a bunch of code doing stuff with DST coercions I'd be very happy. OTOH, I don't think there is anything fundamentally wrong with them, so it would not be a waste of time for the libs team to take a look.

@photino
Copy link

photino commented Sep 24, 2015

Why is the marker named Unsize? Unsized sounds better, since we already have Sized.

@arielb1
Copy link
Contributor

arielb1 commented Sep 24, 2015

@photino

It goes the wrong way around - for example, we have [i8; 2]: Unsize<[u8]> (and also [i8; 2]: Unsize<fmt::Debug>). We can swap the order of parameters - U: Unsized<T> if U is thean unsized version of T.

@rphmeier
Copy link
Contributor

Can we move to stabilize this? It's been unchanged for 5 months and I've heard no complaints about it.

@Gankra
Copy link
Contributor

Gankra commented Dec 18, 2015

I don't recall having any issues with this in libstd. The correct way to use this is basically a witchcraft incantation (mostly because these are under-the-covers things one never interacts with in real code), but as far as I know, there's know way to use it dangerously wrong? The whole thing Just Works.

I guess one thing I've never really thought about is why one needs to talk about whether the pointed-to value is unsizeable or whatever. Why can't one simply declare that pointer X is an unsizable one, and have all that junk automatic? Is this desirable to have for generic consumers...?

@jnicholls
Copy link

It's desirable for generic consumers of e.g. Arena allocators that allocate a Sized type that implements a trait unknown to the allocator, and the consumer wants to coerce the allocated result to an allocated trait object.

See https://gitlab.com/Bastacyclop/rust_arena/blob/master/src/lib.rs in the tests. It's a decent use case. How would you recommend doing this otherwise?

@stevenblenkinsop
Copy link

Is the lack of support for enums deliberate, temporary, or merely overlooked?

@aturon
Copy link
Member Author

aturon commented Feb 1, 2016

I'm nominating this for discussion at the next lang team meeting.

@Gankra
Copy link
Contributor

Gankra commented Feb 2, 2016

@jnicholls maybe I'm missing something, but just mark the one pointer field that will be Unsized as coercable: https://gitlab.com/Bastacyclop/rust_arena/blob/master/src/lib.rs#L41

It seems to me that all the impl<...> CoerceUnsized for ... is trivially derivable from the claim that that field should be coercable.

@jnicholls
Copy link

@gankro Sorry I don't follow what you mean. Can you provide an example?

@Gankra
Copy link
Contributor

Gankra commented Feb 2, 2016

Oops, something clobbered my selection, I meant to link to: https://gitlab.com/Bastacyclop/rust_arena/blob/master/src/lib.rs#L59

Basically instead of

pub struct Allocated<'a, 'b, T: 'b + ?Sized> {
    reference: &'b mut T,
    phantom: PhantomData<&'a ()>
}

impl<'a, 'b, T: ?Sized, U: ?Sized> CoerceUnsized<Allocated<'a, 'b, U>> for Allocated<'a, 'b, T>
    where U: 'b, T: 'b + Unsize<U> {}

You would just do something like:

#[coerce_unsized(T)]
pub struct Allocated<'a, 'b, T: 'b + ?Sized> {
    reference: &'b mut T,
    phantom: PhantomData<&'a ()>
}

@aturon aturon removed the T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. label Feb 18, 2016
@aturon
Copy link
Member Author

aturon commented Feb 18, 2016

cc @eddyb

@aturon
Copy link
Member Author

aturon commented Feb 18, 2016

Removed T-libs tag, but note that we'd like to review the naming conventions here before stabilization.

@eddyb
Copy link
Member

eddyb commented Feb 18, 2016

There's room for generalization and a good chance we might want Source: Coerce<Target>.
See this comment in response to wanting &mut T reborrows working through structs.

@apasel422
Copy link
Contributor

Right now, because T does not implement Unsize<T>, one cannot use CoerceUnsized to support optional coercions in a generic context. (My use case is supporting DSTs with the placement API). Since &T can trivially be coerced to &T, would it make sense to add the identity impl?

@tomaka
Copy link
Contributor

tomaka commented Feb 23, 2016

I'm not very familiar with how this works, but shouldn't the T of CoerceUnsized be T: ?Sized?
Right now T is required to be Sized, which doesn't make sense for me. Example.

@arielb1
Copy link
Contributor

arielb1 commented Feb 23, 2016

@tomaka

You implement CoerceUnsized on pointer types, not on DST types.

e.g.

impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}

@alexcrichton alexcrichton added T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. and removed T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. labels Mar 7, 2016
@alexcrichton
Copy link
Member

(adding T-libs as this has a library API associated with it which needs stabilization)

@nikomatsakis
Copy link
Contributor

So at a recent @rust-lang/lang meeting we discussed this. I think everyone felt...somewhat comfortable with the idea of going forward, but we also wanted to do a thorough review of the current status of the code, along with a comparison against the existing specifications, to make sure everything is well aligned.

@eddyb
Copy link
Member

eddyb commented Mar 11, 2016

@nikomatsakis The problem, though, is that the RFC is intentionally provisional, mostly to get Rc and Arc working with DSTs. I would like to see an attempt at generalization before stabilizing it (I believe the compiler code would "just work" with more than one field being coerced, and various coercion modes, not just Unsize, with minimal changes).

Maybe with specialization we can even encode Deref coercions in a general Coerce trait.

@nikomatsakis
Copy link
Contributor

@eddyb we discussed in @rust-lang/lang meeting today -- splitting off into two feature gates makes sense, provided we have a good description of what the two gates cover and the interaction between them. (e.g., as the issue comments)

@matthieu-m
Copy link
Contributor

Has any consideration been given to having T: Unsize<T> for Sized types?

When attempting to use Unsize in generic contexts, such as in this example, the inability to abstract over sized and unsized types requires splitting APIs in 2, with the same code in each, just because T: !Unsize<T>.

@Chronos-Sk
Copy link

@matthieu-m That playground example is currently throwing an ICE, in case that's new. Error gist.

@matthieu-m
Copy link
Contributor

@matthieu-m That playground example is currently throwing an ICE, in case that's new. Error gist.

I think this is new, but as I mentioned because T: !Unsize<T> it didn't compile in the first place.

@eggyal
Copy link
Contributor

eggyal commented Sep 29, 2021

Currently, there's no std/core type for a "sized str" (by which I mean an array of UTF-8 bytes). Of course, one can create a custom version:

use core::str;

#[repr(transparent)]
pub struct Str<const N: usize>([u8; N]);

impl<const N: usize> Str<N> {
    pub fn new(s: [u8; N]) -> Result<Self, str::Utf8Error> {
        str::from_utf8(&s)?;
        Ok(Self(s))
    }

    pub unsafe fn new_unchecked(s: [u8; N]) -> Self {
        Self(s)
    }
}

But such a custom type cannot be "unsized" to str. Shouldn't there be a library type like this, but that implements Unsize<str>?

@bjorn3
Copy link
Member

bjorn3 commented Sep 29, 2021

impl<const N: usize> Deref for Str<N> {
    type Target = str;
    
    fn deref(&self) -> &str {
        unsafe {
            str::from_utf8_unchecked(&self.0)
        }
    }
}

allows you to "unsize" &Str<N> to &str using &*s.

@eggyal
Copy link
Contributor

eggyal commented Sep 29, 2021

@bjorn3 Of course, but that's not a coercion (the point of this feature, no?). In particular, given s: Str<N>, one cannot write &s as &str—and hence when coercing generic T: Unsize<U> with &t as &U we cannot provide a Str<N> for t.

@joshtriplett joshtriplett added the S-tracking-needs-summary Status: It's hard to tell what's been done and what hasn't! Someone should do some investigation. label Nov 10, 2021
@JanBeh
Copy link
Contributor

JanBeh commented May 25, 2022

I have a problem where I want to be generic over reference-like types, and I feel like the current mechanism doesn't allow me something what I would like to do.

@RReverser
Copy link
Contributor

one cannot write &s as &str

Yes, they can, that's what Deref provides. Your example of &s as &str compiles just fine: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=bd56db69728b59c755a066c9e42ef37c

@eggyal
Copy link
Contributor

eggyal commented Oct 11, 2022

Yes, they can, that's what Deref provides.

Apologies, perhaps my previous comment could have been clearer: a deref coercion is not an unsize coercion. What one cannot do (without either some relaxation of coherence rules or else Str being in the standard library together with an implementation of Unsize<str>) is use Str<N> in a generic context that will perform an unsize coercion (ie where an implementation of Unsize<str> is required), for example:

fn generic<U: ?Sized>(t: impl Unsize<U>) {
    todo!() // something involving &t as &U
}

fn foo<const N: usize>(s: Str<N>) {
    generic::<str>(s); // Str<N> does not implement Unsize<str>
}

For context, this is what prevents strings being "thinnable" in my (experimental) thinnable crate.

@dest1n1s
Copy link

Is there something wrong with the rule

Types implementing a trait Trait also implement Unsize<dyn Trait>.

when it works with a trait object with associate type, such as dyn Trait<Assoc=Type>?

For example:

trait Foo {
    fn foo(&self);
}

trait Bar: Foo {
    type Assoc;

    fn bar(&self);
}

fn upcast<Dyn>(bar: &Dyn) -> &dyn Foo
where
    Dyn: ?Sized + Unsize<dyn Foo>,
{
    bar
}

impl Foo for i32 {
    fn foo(&self) {
        println!("foo");
    }
}

impl Bar for i32 {
    type Assoc = i32;

    fn bar(&self) {
        println!("bar");
    }
}

fn main() {
    let bar: &dyn Bar<Assoc = i32> = &42;
    let foo = upcast(bar);
    foo.foo();
}

in which the compiler says

the trait Unsize<(dyn Foo + 'static)> is not implemented for dyn Bar<Assoc = i32>

But if I try to manually impl the trait Foo for dyn Bar<Assoc=i32>, it says

(dyn Bar<Assoc = i32> + 'static) automatically implements trait Foo

Here's the minimal example: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=85925cd4977fc95beb52ce9a03653755 ,

@Chronos-Sk
Copy link

FWIW, that's effectively relying on the incomplete feature trait_upcasting (which seems to have the same difficulty: playground).

@nikomatsakis
Copy link
Contributor

Closing in favor of #18598 -- they seem to cover the same ground.

matthiaskrgr pushed a commit to matthiaskrgr/rust that referenced this issue Dec 20, 2022
…g#18598

Issue rust-lang#27732 was closed as a duplicate of rust-lang#18598.

Signed-off-by: Anders Kaseorg <andersk@mit.edu>
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Dec 20, 2022
…=Dylan-DPC

Update coerce_unsized tracking issue from rust-lang#27732 to rust-lang#18598

Issue rust-lang#27732 was closed as a duplicate of rust-lang#18598.
bors added a commit to rust-lang-ci/rust that referenced this issue Dec 20, 2022
…iaskrgr

Rollup of 7 pull requests

Successful merges:

 - rust-lang#105835 (Refactor post borrowck cleanup passes)
 - rust-lang#105930 (Disable `NormalizeArrayLen`)
 - rust-lang#105938 (Update coerce_unsized tracking issue from rust-lang#27732 to rust-lang#18598)
 - rust-lang#105939 (Improve description of struct-fields GUI test)
 - rust-lang#105943 (Add regression test for rust-lang#102206)
 - rust-lang#105944 (Add regression test for rust-lang#80816)
 - rust-lang#105945 (Add regression test for rust-lang#57404)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-coercions Area: implicit and explicit `expr as Type` coercions A-DSTs Area: Dynamically-sized types (DSTs) B-RFC-implemented Blocker: Approved by a merged RFC and implemented. B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC Libs-Tracked Libs issues that are tracked on the team's project board. S-tracking-needs-summary Status: It's hard to tell what's been done and what hasn't! Someone should do some investigation. T-lang Relevant to the language team, which will review and decide on the PR/issue. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests