Skip to content

Commit e0d71f5

Browse files
authored
Rollup merge of #97373 - dimpolo:cell_dispatch_from_dyn, r=dtolnay
impl DispatchFromDyn for Cell and UnsafeCell After some fruitful discussion on [Internals](https://internals.rust-lang.org/t/impl-dispatchfromdyn-for-cell-2/16520) here's my first PR to rust-lang/rust 🎉 Please let me know if there's something I missed. This adds `DispatchFromDyn` impls for `Cell`, `UnsafeCell` and `SyncUnsafeCell`. An existing test is also expanded to test the `Cell` impl (which requires the `UnsafeCell` impl) The different `RefCell` types can not implement `DispatchFromDyn` since they have more than one (non ZST) field. &nbsp; **Edit:** ### What: These changes allow one to make types like `MyRc`(code below), to be object safe method receivers after implementing `DispatchFromDyn` and `Deref` for them. This allows for code like this: ```rust struct MyRc<T: ?Sized>(Cell<NonNull<RcBox<T>>>); /* impls for DispatchFromDyn, CoerceUnsized and Deref for MyRc*/ trait Trait { fn foo(self: MyRc<Self>); } let impls_trait = ...; let rc = MyRc::new(impls_trait) as MyRc<dyn Trait>; rc.foo(); ``` Note: `Cell` and `UnsafeCell` won't directly become valid method receivers since they don't implement `Deref`. Making use of these changes requires a wrapper type and nightly features. ### Why: A custom pointer type with interior mutability allows one to store extra information in the pointer itself. These changes allow for such a type to be a method receiver. ### Examples: My use case is a cycle aware custom `Rc` implementation that when dropping a cycle marks some references dangling. On the [forum](https://internals.rust-lang.org/t/impl-dispatchfromdyn-for-cell/14762/8) andersk mentioned that they track if a `Gc` reference is rooted with an extra bit in the reference itself.
2 parents 885bf62 + af58854 commit e0d71f5

6 files changed

+155
-1
lines changed

library/core/src/cell.rs

+32-1
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ use crate::cmp::Ordering;
196196
use crate::fmt::{self, Debug, Display};
197197
use crate::marker::{PhantomData, Unsize};
198198
use crate::mem;
199-
use crate::ops::{CoerceUnsized, Deref, DerefMut};
199+
use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn};
200200
use crate::ptr::{self, NonNull};
201201

202202
mod lazy;
@@ -571,6 +571,16 @@ impl<T: Default> Cell<T> {
571571
#[unstable(feature = "coerce_unsized", issue = "18598")]
572572
impl<T: CoerceUnsized<U>, U> CoerceUnsized<Cell<U>> for Cell<T> {}
573573

574+
// Allow types that wrap `Cell` to also implement `DispatchFromDyn`
575+
// and become object safe method receivers.
576+
// Note that currently `Cell` itself cannot be a method receiver
577+
// because it does not implement Deref.
578+
// In other words:
579+
// `self: Cell<&Self>` won't work
580+
// `self: CellWrapper<Self>` becomes possible
581+
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
582+
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Cell<U>> for Cell<T> {}
583+
574584
impl<T> Cell<[T]> {
575585
/// Returns a `&[Cell<T>]` from a `&Cell<[T]>`
576586
///
@@ -2078,6 +2088,16 @@ impl<T> const From<T> for UnsafeCell<T> {
20782088
#[unstable(feature = "coerce_unsized", issue = "18598")]
20792089
impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafeCell<U>> for UnsafeCell<T> {}
20802090

2091+
// Allow types that wrap `UnsafeCell` to also implement `DispatchFromDyn`
2092+
// and become object safe method receivers.
2093+
// Note that currently `UnsafeCell` itself cannot be a method receiver
2094+
// because it does not implement Deref.
2095+
// In other words:
2096+
// `self: UnsafeCell<&Self>` won't work
2097+
// `self: UnsafeCellWrapper<Self>` becomes possible
2098+
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
2099+
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<UnsafeCell<U>> for UnsafeCell<T> {}
2100+
20812101
/// [`UnsafeCell`], but [`Sync`].
20822102
///
20832103
/// This is just an `UnsafeCell`, except it implements `Sync`
@@ -2169,6 +2189,17 @@ impl<T> const From<T> for SyncUnsafeCell<T> {
21692189
//#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
21702190
impl<T: CoerceUnsized<U>, U> CoerceUnsized<SyncUnsafeCell<U>> for SyncUnsafeCell<T> {}
21712191

2192+
// Allow types that wrap `SyncUnsafeCell` to also implement `DispatchFromDyn`
2193+
// and become object safe method receivers.
2194+
// Note that currently `SyncUnsafeCell` itself cannot be a method receiver
2195+
// because it does not implement Deref.
2196+
// In other words:
2197+
// `self: SyncUnsafeCell<&Self>` won't work
2198+
// `self: SyncUnsafeCellWrapper<Self>` becomes possible
2199+
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
2200+
//#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
2201+
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<SyncUnsafeCell<U>> for SyncUnsafeCell<T> {}
2202+
21722203
#[allow(unused)]
21732204
fn assert_coerce_unsized(
21742205
a: UnsafeCell<&i32>,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Check that even though Cell: DispatchFromDyn it remains an invalid self parameter type
2+
3+
use std::cell::Cell;
4+
5+
trait Trait{
6+
fn cell(self: Cell<&Self>); //~ ERROR invalid `self` parameter type: Cell<&Self>
7+
}
8+
9+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0307]: invalid `self` parameter type: Cell<&Self>
2+
--> $DIR/feature-gate-dispatch-from-dyn-cell.rs:6:19
3+
|
4+
LL | fn cell(self: Cell<&Self>);
5+
| ^^^^^^^^^^^
6+
|
7+
= note: type of `self` must be `Self` or a type that dereferences to it
8+
= help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0307`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Check that a self parameter type requires a DispatchFromDyn impl to be object safe
2+
3+
#![feature(arbitrary_self_types, unsize, coerce_unsized)]
4+
5+
use std::{
6+
marker::Unsize,
7+
ops::{CoerceUnsized, Deref},
8+
};
9+
10+
struct Ptr<T: ?Sized>(Box<T>);
11+
12+
impl<T: ?Sized> Deref for Ptr<T> {
13+
type Target = T;
14+
15+
fn deref(&self) -> &T {
16+
&*self.0
17+
}
18+
}
19+
20+
impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {}
21+
// Because this impl is missing the coercion below fails.
22+
// impl<T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<Ptr<U>> for Ptr<T> {}
23+
24+
trait Trait {
25+
fn ptr(self: Ptr<Self>);
26+
}
27+
impl Trait for i32 {
28+
fn ptr(self: Ptr<Self>) {}
29+
}
30+
31+
fn main() {
32+
Ptr(Box::new(4)) as Ptr<dyn Trait>;
33+
//~^ ERROR the trait `Trait` cannot be made into an object
34+
//~^^ ERROR the trait `Trait` cannot be made into an object
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
error[E0038]: the trait `Trait` cannot be made into an object
2+
--> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:32:25
3+
|
4+
LL | fn ptr(self: Ptr<Self>);
5+
| --------- help: consider changing method `ptr`'s `self` parameter to be `&self`: `&Self`
6+
...
7+
LL | Ptr(Box::new(4)) as Ptr<dyn Trait>;
8+
| ^^^^^^^^^^^^^^ `Trait` cannot be made into an object
9+
|
10+
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
11+
--> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:25:18
12+
|
13+
LL | trait Trait {
14+
| ----- this trait cannot be made into an object...
15+
LL | fn ptr(self: Ptr<Self>);
16+
| ^^^^^^^^^ ...because method `ptr`'s `self` parameter cannot be dispatched on
17+
18+
error[E0038]: the trait `Trait` cannot be made into an object
19+
--> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:32:5
20+
|
21+
LL | fn ptr(self: Ptr<Self>);
22+
| --------- help: consider changing method `ptr`'s `self` parameter to be `&self`: `&Self`
23+
...
24+
LL | Ptr(Box::new(4)) as Ptr<dyn Trait>;
25+
| ^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
26+
|
27+
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
28+
--> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:25:18
29+
|
30+
LL | trait Trait {
31+
| ----- this trait cannot be made into an object...
32+
LL | fn ptr(self: Ptr<Self>);
33+
| ^^^^^^^^^ ...because method `ptr`'s `self` parameter cannot be dispatched on
34+
note: required for `Ptr<{integer}>` to implement `CoerceUnsized<Ptr<dyn Trait>>`
35+
--> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:20:40
36+
|
37+
LL | impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {}
38+
| --------- ^^^^^^^^^^^^^^^^^^^^^ ^^^^^^
39+
| |
40+
| unsatisfied trait bound introduced here
41+
= note: required by cast to type `Ptr<dyn Trait>`
42+
43+
error: aborting due to 2 previous errors
44+
45+
For more information about this error, try `rustc --explain E0038`.

tests/ui/self/arbitrary_self_types_pointers_and_wrappers.rs

+22
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#![feature(rustc_attrs)]
44

55
use std::{
6+
cell::Cell,
67
ops::{Deref, CoerceUnsized, DispatchFromDyn},
78
marker::Unsize,
89
};
@@ -20,6 +21,20 @@ impl<T: ?Sized> Deref for Ptr<T> {
2021
impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {}
2122
impl<T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<Ptr<U>> for Ptr<T> {}
2223

24+
25+
struct CellPtr<'a, T: ?Sized>(Cell<&'a T>);
26+
27+
impl<'a, T: ?Sized> Deref for CellPtr<'a, T> {
28+
type Target = T;
29+
30+
fn deref(&self) -> &T {
31+
self.0.get()
32+
}
33+
}
34+
35+
impl<'a, T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<CellPtr<'a, U>> for CellPtr<'a, T> {}
36+
impl<'a, T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<CellPtr<'a, U>> for CellPtr<'a, T> {}
37+
2338
struct Wrapper<T: ?Sized>(T);
2439

2540
impl<T: ?Sized> Deref for Wrapper<T> {
@@ -42,6 +57,7 @@ trait Trait {
4257
fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32;
4358
fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32;
4459
fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32;
60+
fn cell(self: CellPtr<Self>) -> i32;
4561
}
4662

4763
impl Trait for i32 {
@@ -54,6 +70,9 @@ impl Trait for i32 {
5470
fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32 {
5571
***self
5672
}
73+
fn cell(self: CellPtr<Self>) -> i32 {
74+
*self
75+
}
5776
}
5877

5978
fn main() {
@@ -65,4 +84,7 @@ fn main() {
6584

6685
let wpw = Wrapper(Ptr(Box::new(Wrapper(7)))) as Wrapper<Ptr<Wrapper<dyn Trait>>>;
6786
assert_eq!(wpw.wrapper_ptr_wrapper(), 7);
87+
88+
let c = CellPtr(Cell::new(&8)) as CellPtr<dyn Trait>;
89+
assert_eq!(c.cell(), 8);
6890
}

0 commit comments

Comments
 (0)