Skip to content

Commit

Permalink
[pointer] Match variance of references (#1894)
Browse files Browse the repository at this point in the history
When the aliasing mode is `Any`, `Ptr<'a, T>` is invariant in `'a` and
`T`. When the aliasing mode is `Shared` or `Exclusive`, `Ptr` has the
same variance as `&'a T` and `&'a mut T` respectively.

Makes progress on #1839
  • Loading branch information
joshlf authored Oct 14, 2024
1 parent ca9243f commit 51475bd
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 2 deletions.
19 changes: 19 additions & 0 deletions src/pointer/invariant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ pub trait Aliasing: Sealed {
/// Is `Self` [`Exclusive`]?
#[doc(hidden)]
const IS_EXCLUSIVE: bool;

/// A type which has the correct variance over `'a` and `T` for this
/// aliasing invariant. `Ptr` stores a `<I::Aliasing as
/// Aliasing>::Variance<'a, T>` to inherit this variance.
#[doc(hidden)]
type Variance<'a, T: 'a + ?Sized>;
}

/// The alignment invariant of a [`Ptr`][super::Ptr].
Expand All @@ -51,6 +57,17 @@ pub trait Reference: Aliasing + Sealed {}
pub enum Any {}
impl Aliasing for Any {
const IS_EXCLUSIVE: bool = false;

// SAFETY: Since we don't know what aliasing model this is, we have to be
// conservative. Invariance is strictly more restrictive than any other
// variance model, so this can never cause soundness issues.
//
// `fn() -> T` and `fn(T) -> ()` are covariant and contravariant in `T`,
// respectively. [1] Thus, `fn(T) -> T` is invariant in `T`. Thus, `fn(&'a
// T) -> &'a T` is invariant in `'a` and `T`.
//
// [1] https://doc.rust-lang.org/1.81.0/reference/subtyping.html#variance
type Variance<'a, T: 'a + ?Sized> = fn(&'a T) -> &'a T;
}
impl Alignment for Any {}
impl Validity for Any {}
Expand All @@ -66,6 +83,7 @@ impl Validity for Any {}
pub enum Shared {}
impl Aliasing for Shared {
const IS_EXCLUSIVE: bool = false;
type Variance<'a, T: 'a + ?Sized> = &'a T;
}
impl Reference for Shared {}

Expand All @@ -77,6 +95,7 @@ impl Reference for Shared {}
pub enum Exclusive {}
impl Aliasing for Exclusive {
const IS_EXCLUSIVE: bool = true;
type Variance<'a, T: 'a + ?Sized> = &'a mut T;
}
impl Reference for Exclusive {}

Expand Down
5 changes: 3 additions & 2 deletions src/pointer/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ mod def {
/// [`I::Validity`](invariant::Validity).
// SAFETY: `PtrInner<'a, T>` is covariant over `'a` and `T`.
ptr: PtrInner<'a, T>,
_variance: PhantomData<<I::Aliasing as Aliasing>::Variance<'a, T>>,
_invariants: PhantomData<I>,
}

Expand Down Expand Up @@ -93,7 +94,7 @@ mod def {
let ptr = unsafe { PtrInner::new(ptr) };
// SAFETY: The caller has promised (in 6 - 8) to satisfy all safety
// invariants of `Ptr`.
Self { ptr, _invariants: PhantomData }
Self { ptr, _variance: PhantomData, _invariants: PhantomData }
}

/// Constructs a new `Ptr` from a [`PtrInner`].
Expand All @@ -111,7 +112,7 @@ mod def {
pub(super) const unsafe fn from_inner(ptr: PtrInner<'a, T>) -> Ptr<'a, T, I> {
// SAFETY: The caller has promised to satisfy all safety invariants
// of `Ptr`.
Self { ptr, _invariants: PhantomData }
Self { ptr, _variance: PhantomData, _invariants: PhantomData }
}

/// Converts this `Ptr<T>` to a [`PtrInner<T>`].
Expand Down

0 comments on commit 51475bd

Please sign in to comment.