We add a built in attribute for handling pin projection:
struct MyCombinator<F> {
#[pin_accessor]
field: F,
}
This generates a method fn field_pin(self: PinMut<'_, Self>) -> PinMut<'_, F>
, and also generates these constraints:
for<F> MyCombinator<F>: Unpin implies F: Unpin
for<F> MyCombinator<F>: PinDrop or for<F: MyCombinator<F>: !Drop
This requires no unsafe code to perform pin projections.
The unpin constraint is an implies constraint, we generate a query about the relationship between the field type and the self type. There's no way to generate a constraint like this in the surface syntax of Rust today, but the compiler builtin could.
The current compiler is not structured to solve this kind of constraint, but chalk is. Further integration of strategies from chalk into rustc is necessary before this kind of constraint could be generated.
We add a new, special trait, to the standard library:
trait PinDrop: Drop {
fn pin_drop(self: PinMut<Self>);
}
impl<T: PinDrop> Drop for T {
fn drop(&mut self) {
pinned!(self);
self.pin_drop();
}
}
(This trait is special because this kind of blanket impl is not actually allowed in library Rust, so it would have to be implemented internally).
If a type using the #[pin_accessor]
attribute needs a destructor, it must use the PinDrop
trait, rather than the Drop
trait. That way, it is guaranteed that it does not move out of the tagged field in safe code (unless the field implements Unpin
).