-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Update to a new pinning API. #53877
Update to a new pinning API. #53877
Conversation
3f1811e
to
974bdc8
Compare
The job Click to expand the log.
I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
src/liballoc/boxed.rs
Outdated
#[unstable(feature = "pin", issue = "49150")] | ||
impl<T> From<Box<T>> for Pin<Box<T>> { | ||
fn from(boxed: Box<T>) -> Self { | ||
unsafe { Pin::new_unchecked(boxed) } |
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.
This could use a brief justification why the unsafe
is okay.
src/liballoc/boxed.rs
Outdated
|
||
#[unstable(feature = "pin", issue = "49150")] | ||
pub fn pinned(x: T) -> Pin<Box<T>> { | ||
unsafe { Pin::new_unchecked(box 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.
This could use a brief justification why the unsafe
is okay.
src/libcore/pin.rs
Outdated
#[unstable(feature = "pin", issue = "49150")] | ||
pub fn reborrow<'b>(&'b mut self) -> PinMut<'b, T> { | ||
PinMut { inner: self.inner } | ||
pub fn get(this: Pin<&'a T>) -> &'a T { |
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.
Why do we have set
for all Pin<P> where P: DerefMut<Target = T>
, but get
only for Pin<&T>
?
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.
You can't use 'Deref' here since you want the lifetime to be equal to that of the original reference, not of your borrow of it.
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.
Oh, I see... this is actually the method witnessing that we can safely have shared references to pinned data! It has such an innocent name, I did not realize that. :)
src/libcore/pin.rs
Outdated
fn deref(&self) -> &T { | ||
&*self.inner | ||
&*self.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.
I'd prefer if you could use something like #49150 (comment). In fact, I'd prefer if Pin
could be in its own little private local submodule which only exposes those 4 functions (as_ref
, as_shr
, unpin_mut
, unpin_shr
) and new_unchecked
; and everything else lived outside that module. Just to be sure we do not accidentally unpin something anywhere here.
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.
At the least, this could use get
so that we only have one place witnessing the Pin<&T> -> &T
conversion.
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.
Unfortunately, you can't quite implement it all just using Deref
like that, since Deref
only gives you the lifetime of the borrow, not the lifetime of the original object.
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.
Well there could be some core function that Deref
and this uses.
src/libcore/pin.rs
Outdated
/// | ||
/// This constructor is unsafe because we cannot guarantee that the target data | ||
/// is properly pinned by this pointer. If the constructed `Pin<P>` does not guarantee | ||
/// that the data is "pinned," constructing a `Pin<P>` is undefined behavior and could lead |
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.
The comma is inside the quotes and previously you used italics (*
) rather then qoutes, but it's just a small thing.
I've made some changes, including assorted cleanup, fixing the method resolution issue, making r? @aturon |
This comment has been minimized.
This comment has been minimized.
b2fc5e5
to
166392d
Compare
This comment has been minimized.
This comment has been minimized.
166392d
to
b3a695b
Compare
|
||
/// Get a mutable reference to the data inside of this `Pin`. | ||
/// | ||
/// This requires that the data inside this `Pin` is `Unpin`. |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
@cramertj After you address my comment, r=me. |
b3a695b
to
3ec1810
Compare
@bors r=aturon |
📌 Commit 3ec1810 has been approved by |
⌛ Testing commit 3ec1810 with merge 8bbe4f147d0a8b407cc3a840dd3197dcb0145ed3... |
pub fn new(pointer: P) -> Pin<P> { | ||
// Safety: the value pointed to is `Unpin`, and so has no requirements | ||
// around pinning. | ||
unsafe { Pin::new_unchecked(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.
Is this always okay? We have impl Deref
for non-pointer types as well, and we have no safety contract at all for what you put into P::Target
.
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.
If P::Target
is Unpin
, I'd expect basically what my comment says: that Pin<ThingThatTargetsT>
is semantically equivalent to ThingThatTargetsT
(no pinning invariant exists).
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.
I find that a rather surprising interaction. I might implement Deref
like e.g. TyCtxt
does, to "inherit" a whole bunch of methods from one of the members, and I will then usually not expect any interaction of that with pinning.
Or I might have a PinnedBox
that does propagate pinning (that's safe, as long as Unpin
is only conditionally implemented). Naturally I want Deref
for PinnedBox
.
When this new Pin
API was introduced, it was clear that the "key point" here are the constructors that create a Pin
. We discussed either making this manually for all types, or having a new unsafe trait that lets you do this. I do not remember seeing any blanket implementation like this that relies on an existing safe trait, and I am pretty worried about soundness of this. I'd feel much better if we could remove this part. What is the motivation?
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.
IMO this new API was always just a different way to spell PinBox
, PinMut
, PinRef
etc. that allowed for reusing some methods. This is one of the places where we get reuse: rather than providing safe new_rc
, new_arc
, new_ref
, and new_mut
functions where T: Unpin
, we can have a single new
method that supplies that bound.
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.
Well, we get reuse and also expand this to every type ever that implements Deref
. That's a big deal.^^ My impression was that constructors of Pin<P>
would be carefully curated, because they are the only thing that's "stopping the flood" and making sure that this is all well-behaved.
That said, I cannot construct a counter-example. Pin<P>
(where P
is not &[mut]
) won't ever do anything except for giving you a Pin<&[mut] P::Target>
, and we check that that's harmless because P::Target: Unpin
. So I am feeling uneasy but cannot actually think of a way in which it would break things.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
src/libcore/pin.rs
Outdated
P::Target: Unpin | ||
{ | ||
fn deref_mut(&mut self) -> &mut P::Target { | ||
&mut *self.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.
Actually, couldn't you implement this as Pin::get_mut(self.as_mut())
?
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.
I think so, yes.
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.
Yay. :)
However, now the comments above as_mut
/as_ref
don't match reality any more, do they?
@bors r=aturon |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
85508e2
to
574bca7
Compare
@bors r=aturon |
📌 Commit 574bca7 has been approved by |
☀️ Test successful - status-appveyor, status-travis |
Blocked on #53843 because of method resolution problems with new pin type.@r? @cramertj
cc @RalfJung @pythonesque anyone interested in #49150