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

Some way to simulate `&mut` reborrows in user code #1403

Open
nikomatsakis opened this Issue Dec 10, 2015 · 12 comments

Comments

Projects
None yet
@nikomatsakis
Copy link
Contributor

nikomatsakis commented Dec 10, 2015

@carllerche wanted a way to make a newtyped &mut that would reborrow in the same implicit way that reborrows do today. That is, with an &mut, foo(ptr) is roughly equivalent to foo(&mut *ptr), but if ptr is MyRef<'a>(&'a mut ...), then this will not coerce from MyRef<'a> to MyRef<'b> (where 'a:'b).

@dgrunwald

This comment has been minimized.

Copy link
Contributor

dgrunwald commented Dec 11, 2015

In one of the designs for rust-cpython that I explored; I ran into a similar issue:
I had a zero-sized struct (newtype around PhantomData<&mut 'p ()>), which could not be Copy (unsafe code relied on the fact that user code had access to at most one instance of the struct at a time).
But this struct still had to be passed around between function calls; which needs something like re-borrowing to avoid the code becoming unwieldy.

In my case, I ended up going with a different design where the struct could be Copy instead. (although there were more reasons for that than the lack of reborrowing)

@carllerche

This comment has been minimized.

Copy link
Member

carllerche commented Dec 14, 2015

+1. Commenting to track.

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented Dec 23, 2015

We could handle this similarly to unsizing coercions - see Rc's CoerceUnsized impl, which "only" require that it has a single field also implementing CoerceUnsized, and this repeats all the way down to the primitive impls (specified in #982).

So if we generalized, impl<T: ?Sized, U: ?Sized> Coerce<Rc<U>> for Rc<T> would require that *mut T: Coerce<*mut U> which can be satisfied with an T: Unsize<U> bound.

And impl<'a, 'b> Coerce<MyRef<'b>> for MyRef<'a> would require 'a: 'b and borrowck would treat it as a reborrow.

Should it work on multiple fields, including mixed coercions, e.g. one unsizing and one reborrowing, in different fields?

FWIW, we currently kind of support reborrowing combined with unsizing due to the way the CoerceUnsized impls for &T and &mut T are generic over both input and output lifetimes, so impl CoerceUnsized<MyRef<'b, U>> for MyRef<'a, T> would work, but borrowck may not understand it as a reborrow.

@carllerche

This comment has been minimized.

Copy link
Member

carllerche commented Dec 28, 2015

@eddyb In my case, my type has multiple fields. If I understand your comment, then implementing CoerceUnsized wouldn't work?

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented Dec 28, 2015

@carllerche implementing CoerceUnsized doesn't work unless you have an unsizing and it doesn't even result in a reborrow.
I'm talking about extending the mechanism to allow all coercions to happen inside user-defined types, with opt-in at the definition site.

Personally, I think Option<&mut T> having reborrows would be quite handy.

@SimonSapin

This comment has been minimized.

Copy link
Contributor

SimonSapin commented Feb 20, 2016

Personally, I think Option<&mut T> having reborrows would be quite handy.

Yes, please. In one piece of code that really should have used Option<&mut HashSet<Name>> I’ve ended up using &mut Option<HashSet<Name>> in order to get re-borrows.

@pnkfelix

This comment has been minimized.

Copy link
Member

pnkfelix commented Feb 24, 2016

cc me

@soltanmm

This comment has been minimized.

Copy link

soltanmm commented Mar 2, 2016

This is sort of possible today. Consider the following (messy, off-the-top-of-my-head, borderline embarrassing) associated-type-encoded-HKTs-based formulation:

pub trait Reborrowable<'a> {
    type Result;
}
pub trait ReborrowMut<'self_>: for<'a> Reborrowable<'a> + Reborrowable<'self_, Result=Self> {
    fn reborrow<'reborrow>(&'reborrow mut self)
        -> <Self as Reborrowable<'reborrow>>::Result
        where 'self_: 'reborrow;
}

This can be used as so: https://gist.github.com/anonymous/4aa1bfddaf5efdb53b15 (sans the type-identity trait bound to ensure Reborrowable is well-behaved; I believe that particular bit not working is merely a bug rather than a missing feature).

I'm not saying that this is a solution - far from it. Still, it's possible to within a single function call on a trait (which is just about what the Deref trait does with autoderef'ing).

@dwrensha

This comment has been minimized.

Copy link

dwrensha commented Apr 30, 2016

@sgrif

This comment has been minimized.

Copy link
Contributor

sgrif commented May 9, 2017

Ran into a need for this today.

@dhardy

This comment has been minimized.

Copy link
Contributor

dhardy commented Mar 1, 2018

I've run into this twice now.

Edit: better example
Also see: rust-random/rand#287

@carllerche

This comment has been minimized.

Copy link
Member

carllerche commented Mar 1, 2018

This would also be super helpful for iovec which is used heavily as part of Mio / Tokio / the bytes crate, etc... for vectored operations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.