Skip to content

Commit 3ab2c00

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 5879a7e commit 3ab2c00

File tree

1 file changed

+21
-2
lines changed

1 file changed

+21
-2
lines changed

src/pointer/ptr.rs

Lines changed: 21 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>`].
@@ -152,6 +153,12 @@ pub mod invariant {
152153
/// Is `Self` [`Exclusive`]?
153154
#[doc(hidden)]
154155
const IS_EXCLUSIVE: bool;
156+
157+
/// A type which has the correct variance over `'a` and `T` for this
158+
/// aliasing invariant. `Ptr` stores a `<I::Aliasing as
159+
/// Aliasing>::Variance<'a, T>` to inherit this variance.
160+
#[doc(hidden)]
161+
type Variance<'a, T: 'a + ?Sized>;
155162
}
156163

157164
/// The alignment invariant of a [`Ptr`][super::Ptr].
@@ -172,6 +179,16 @@ pub mod invariant {
172179
pub enum Any {}
173180
impl Aliasing for Any {
174181
const IS_EXCLUSIVE: bool = false;
182+
// SAFETY: Since we don't know what aliasing model this is, we have to
183+
// be conservative. Invariance is strictly more restrictive than any
184+
// other variance model, so this can never cause soundness issues.
185+
//
186+
// `fn() -> T` and `fn(T) -> ()` are covariant and contravariant in `T`,
187+
// respectively. [1] Thus, `fn(T) -> T` is invariant in `T`. Thus,
188+
// `fn(&'a T) -> &'a T` is invariant in `'a` and `T`.
189+
//
190+
// [1] https://doc.rust-lang.org/1.81.0/reference/subtyping.html#variance
191+
type Variance<'a, T: 'a + ?Sized> = fn(&'a T) -> &'a T;
175192
}
176193
impl Alignment for Any {}
177194
impl Validity for Any {}
@@ -188,6 +205,7 @@ pub mod invariant {
188205
pub enum Shared {}
189206
impl Aliasing for Shared {
190207
const IS_EXCLUSIVE: bool = false;
208+
type Variance<'a, T: 'a + ?Sized> = &'a T;
191209
}
192210
impl Reference for Shared {}
193211

@@ -199,6 +217,7 @@ pub mod invariant {
199217
pub enum Exclusive {}
200218
impl Aliasing for Exclusive {
201219
const IS_EXCLUSIVE: bool = true;
220+
type Variance<'a, T: 'a + ?Sized> = &'a mut T;
202221
}
203222
impl Reference for Exclusive {}
204223

0 commit comments

Comments
 (0)