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

Remove P: Unpin bound on impl Future for Pin #81363

Merged
merged 4 commits into from
Jul 29, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions library/core/src/future/future.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,11 @@ impl<F: ?Sized + Future + Unpin> Future for &mut F {
#[stable(feature = "futures_api", since = "1.36.0")]
impl<P> Future for Pin<P>
where
P: Unpin + ops::DerefMut<Target: Future>,
P: ops::DerefMut<Target: Future>,
{
type Output = <<P as ops::Deref>::Target as Future>::Output;

fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
Pin::get_mut(self).as_mut().poll(cx)
<P::Target as Future>::poll(self.as_deref_mut(), cx)
}
}
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@
#![feature(exhaustive_patterns)]
#![feature(no_core)]
#![feature(auto_traits)]
#![feature(pin_deref_mut)]
#![feature(prelude_import)]
#![feature(ptr_metadata)]
#![feature(repr_simd, platform_intrinsics)]
Expand Down
38 changes: 38 additions & 0 deletions library/core/src/pin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,44 @@ impl<T: ?Sized> Pin<&'static T> {
}
}

impl<'a, P: DerefMut> Pin<&'a mut Pin<P>> {
/// Gets a pinned mutable reference from this nested pinned pointer.
///
/// This is a generic method to go from `Pin<&mut Pin<Pointer<T>>>` to `Pin<&mut T>`. It is
/// safe because the existence of a `Pin<Pointer<T>>` ensures that the pointee, `T`, cannot
/// move in the future, and this method does not enable the pointee to move. "Malicious"
/// implementations of `Pointer::DerefMut` are likewise ruled out by the contract of
jonhoo marked this conversation as resolved.
Show resolved Hide resolved
/// `Pin::new_unchecked`.
jonhoo marked this conversation as resolved.
Show resolved Hide resolved
#[unstable(feature = "pin_deref_mut", issue = "none")]
jonhoo marked this conversation as resolved.
Show resolved Hide resolved
#[inline(always)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We generally use #[inline] and only use #[inline(always)] when really necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used #[inline(always)] because that annotation is used on both as_mut and get_mut, and so it feels like the logic that applies there would apply here, but I could be wrong. Happy to change if preferred.

pub fn as_deref_mut(self) -> Pin<&'a mut P::Target> {
// SAFETY: What we're asserting here is that going from
//
// Pin<&mut Pin<P>>
//
// to
//
// Pin<&mut P::Target>
//
// is safe.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My own justification attempts to follow the invariant I sketched here.

First of all, it seems like Pin might actually be Unpin. This might sound surprising, but really what Unpin means is that the "pinned" and "not-pinned" typestates of a type are the same, and Pin is always referring to pinned data, so whether it is in one or the other typestate makes no difference.

Thus we can turn Pin<&'a mut Pin<P>> into &'a mut Pin<P> via get_mut. Now we just call as_mut and we are done.

//
// We need to ensure that two things hold for that to be the case:
//
// 1) Once we give out a `Pin<&mut P::Target>`, an `&mut P::Target` will not be given out.
// 2) By giving out a `Pin<&mut P::Target>`, we do not risk of violating `Pin<&mut Pin<P>>`
//
// The existence of `Pin<P>` is sufficient to guarantee #1: since we already have a
// `Pin<P>`, it must already uphold the pinning guarantees, which must mean that
// `Pin<&mut P::Target>` does as well, since `Pin::as_mut` is safe. We do not have to rely
// on the fact that P is _also_ pinned.
//
// For #2, we need to ensure that code given a `Pin<&mut P::Target>` cannot cause the
// `Pin<P>` to move? That is not possible, since `Pin<&mut P::Target>` no longer retains
// any access to the `P` itself, much less the `Pin<P>`.
unsafe { self.get_unchecked_mut() }.as_mut()
}
}

impl<T: ?Sized> Pin<&'static mut T> {
/// Get a pinned mutable reference from a static mutable reference.
///
Expand Down