Skip to content

Commit 77362c9

Browse files
committed
[pointer] Match variance of references
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
1 parent 5f9ae12 commit 77362c9

File tree

2 files changed

+22
-2
lines changed

2 files changed

+22
-2
lines changed

src/pointer/invariant.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ pub trait Aliasing: Sealed {
3131
/// Is `Self` [`Exclusive`]?
3232
#[doc(hidden)]
3333
const IS_EXCLUSIVE: bool;
34+
35+
/// A type which has the correct variance over `'a` and `T` for this
36+
/// aliasing invariant. `Ptr` stores a `<I::Aliasing as
37+
/// Aliasing>::Variance<'a, T>` to inherit this variance.
38+
#[doc(hidden)]
39+
type Variance<'a, T: 'a + ?Sized>;
3440
}
3541

3642
/// The alignment invariant of a [`Ptr`][super::Ptr].
@@ -51,6 +57,17 @@ pub trait Reference: Aliasing + Sealed {}
5157
pub enum Any {}
5258
impl Aliasing for Any {
5359
const IS_EXCLUSIVE: bool = false;
60+
61+
// SAFETY: Since we don't know what aliasing model this is, we have to be
62+
// conservative. Invariance is strictly more restrictive than any other
63+
// variance model, so this can never cause soundness issues.
64+
//
65+
// `fn() -> T` and `fn(T) -> ()` are covariant and contravariant in `T`,
66+
// respectively. [1] Thus, `fn(T) -> T` is invariant in `T`. Thus, `fn(&'a
67+
// T) -> &'a T` is invariant in `'a` and `T`.
68+
//
69+
// [1] https://doc.rust-lang.org/1.81.0/reference/subtyping.html#variance
70+
type Variance<'a, T: 'a + ?Sized> = fn(&'a T) -> &'a T;
5471
}
5572
impl Alignment for Any {}
5673
impl Validity for Any {}
@@ -66,6 +83,7 @@ impl Validity for Any {}
6683
pub enum Shared {}
6784
impl Aliasing for Shared {
6885
const IS_EXCLUSIVE: bool = false;
86+
type Variance<'a, T: 'a + ?Sized> = &'a T;
6987
}
7088
impl Reference for Shared {}
7189

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

src/pointer/ptr.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ mod def {
5656
/// [`I::Validity`](invariant::Validity).
5757
// SAFETY: `PtrInner<'a, T>` is covariant over `'a` and `T`.
5858
ptr: PtrInner<'a, T>,
59+
_variance: PhantomData<<I::Aliasing as Aliasing>::Variance<'a, T>>,
5960
_invariants: PhantomData<I>,
6061
}
6162

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

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

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

0 commit comments

Comments
 (0)