Skip to content

Commit 3fc70e8

Browse files
committed
Auto merge of #54383 - mikeyhew:custom-receivers-object-safety, r=nikomatsakis
Take 2: Implement object-safety and dynamic dispatch for arbitrary_self_types This replaces #50173. Over the months that that PR was open, we made a lot of changes to the way this was going to be implemented, and the long, meandering comment thread and commit history would have been confusing to people reading it in the future. So I decided to package everything up with new, straighforward commits and open a new PR. Here are the main points. Please read the commit messages for details. - To simplify codegen, we only support receivers that have the ABI of a pointer. That means they are builtin pointer types, or newtypes thereof. - We introduce a new trait: `DispatchFromDyn<T>`, similar to `CoerceUnsized<T>`. `DispatchFromDyn` has extra requirements that `CoerceUnsized` does not: when you implement `DispatchFromDyn` for a struct, there cannot be any extra fields besides the field being coerced and `PhantomData` fields. This ensures that the struct's ABI is the same as a pointer. - For a method's receiver (e.g. `self: Rc<Self>`) to be object-safe, it needs to have the following property: - let `DynReceiver` be the receiver when `Self = dyn Trait` - let `ConcreteReceiver` be the receiver when `Self = T`, where `T` is some unknown `Sized` type that implements `Trait`, and is the erased type of the trait object. - `ConcreteReceiver` must implement `DispatchFromDyn<DynReceiver>` In the case of `Rc<Self>`, this requires `Rc<T>: DispatchFromDyn<Rc<dyn Trait>>` These rules are explained more thoroughly in the doc comment on `receiver_is_dispatchable` in object_safety.rs. r? @nikomatsakis and @eddyb cc @arielb1 @cramertj @withoutboats Special thanks to @nikomatsakis for getting me un-stuck when implementing the object-safety checks, and @eddyb for helping with the codegen parts. EDIT 2018-11-01: updated because CoerceSized has been replaced with DispatchFromDyn
2 parents 8b09631 + 192e7c4 commit 3fc70e8

30 files changed

+904
-128
lines changed

src/liballoc/boxed.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ use core::iter::FusedIterator;
7777
use core::marker::{Unpin, Unsize};
7878
use core::mem;
7979
use core::pin::Pin;
80-
use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState};
80+
use core::ops::{CoerceUnsized, DispatchFromDyn, Deref, DerefMut, Generator, GeneratorState};
8181
use core::ptr::{self, NonNull, Unique};
8282
use core::task::{LocalWaker, Poll};
8383

@@ -696,6 +696,9 @@ impl<'a, A, R> FnOnce<A> for Box<dyn FnBox<A, Output = R> + Send + 'a> {
696696
#[unstable(feature = "coerce_unsized", issue = "27732")]
697697
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Box<U>> for Box<T> {}
698698

699+
#[unstable(feature = "dispatch_from_dyn", issue = "0")]
700+
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T> {}
701+
699702
#[stable(feature = "box_slice_clone", since = "1.3.0")]
700703
impl<T: Clone> Clone for Box<[T]> {
701704
fn clone(&self) -> Self {

src/liballoc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
#![feature(box_syntax)]
8787
#![feature(cfg_target_has_atomic)]
8888
#![feature(coerce_unsized)]
89+
#![feature(dispatch_from_dyn)]
8990
#![feature(core_intrinsics)]
9091
#![feature(custom_attribute)]
9192
#![feature(dropck_eyepatch)]

src/liballoc/rc.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ use core::marker;
255255
use core::marker::{Unpin, Unsize, PhantomData};
256256
use core::mem::{self, align_of_val, forget, size_of_val};
257257
use core::ops::Deref;
258-
use core::ops::CoerceUnsized;
258+
use core::ops::{CoerceUnsized, DispatchFromDyn};
259259
use core::pin::Pin;
260260
use core::ptr::{self, NonNull};
261261
use core::convert::From;
@@ -297,6 +297,9 @@ impl<T: ?Sized> !marker::Sync for Rc<T> {}
297297
#[unstable(feature = "coerce_unsized", issue = "27732")]
298298
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Rc<U>> for Rc<T> {}
299299

300+
#[unstable(feature = "dispatch_from_dyn", issue = "0")]
301+
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Rc<U>> for Rc<T> {}
302+
300303
impl<T> Rc<T> {
301304
/// Constructs a new `Rc<T>`.
302305
///
@@ -1176,6 +1179,9 @@ impl<T: ?Sized> !marker::Sync for Weak<T> {}
11761179
#[unstable(feature = "coerce_unsized", issue = "27732")]
11771180
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Weak<U>> for Weak<T> {}
11781181

1182+
#[unstable(feature = "dispatch_from_dyn", issue = "0")]
1183+
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Weak<U>> for Weak<T> {}
1184+
11791185
impl<T> Weak<T> {
11801186
/// Constructs a new `Weak<T>`, without allocating any memory.
11811187
/// Calling [`upgrade`][Weak::upgrade] on the return value always gives [`None`].

src/liballoc/sync.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use core::cmp::Ordering;
2525
use core::intrinsics::abort;
2626
use core::mem::{self, align_of_val, size_of_val};
2727
use core::ops::Deref;
28-
use core::ops::CoerceUnsized;
28+
use core::ops::{CoerceUnsized, DispatchFromDyn};
2929
use core::pin::Pin;
3030
use core::ptr::{self, NonNull};
3131
use core::marker::{Unpin, Unsize, PhantomData};
@@ -214,6 +214,9 @@ unsafe impl<T: ?Sized + Sync + Send> Sync for Arc<T> {}
214214
#[unstable(feature = "coerce_unsized", issue = "27732")]
215215
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Arc<U>> for Arc<T> {}
216216

217+
#[unstable(feature = "dispatch_from_dyn", issue = "0")]
218+
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Arc<U>> for Arc<T> {}
219+
217220
/// `Weak` is a version of [`Arc`] that holds a non-owning reference to the
218221
/// managed value. The value is accessed by calling [`upgrade`] on the `Weak`
219222
/// pointer, which returns an [`Option`]`<`[`Arc`]`<T>>`.
@@ -254,6 +257,8 @@ unsafe impl<T: ?Sized + Sync + Send> Sync for Weak<T> {}
254257

255258
#[unstable(feature = "coerce_unsized", issue = "27732")]
256259
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Weak<U>> for Weak<T> {}
260+
#[unstable(feature = "dispatch_from_dyn", issue = "0")]
261+
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Weak<U>> for Weak<T> {}
257262

258263
#[stable(feature = "arc_weak", since = "1.4.0")]
259264
impl<T: ?Sized + fmt::Debug> fmt::Debug for Weak<T> {

src/libcore/nonzero.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
//! Exposes the NonZero lang item which provides optimization hints.
1212
13-
use ops::CoerceUnsized;
13+
use ops::{CoerceUnsized, DispatchFromDyn};
1414

1515
/// A wrapper type for raw pointers and integers that will never be
1616
/// NULL or 0 that might allow certain optimizations.
@@ -20,3 +20,5 @@ use ops::CoerceUnsized;
2020
pub(crate) struct NonZero<T>(pub(crate) T);
2121

2222
impl<T: CoerceUnsized<U>, U> CoerceUnsized<NonZero<U>> for NonZero<T> {}
23+
24+
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<NonZero<U>> for NonZero<T> {}

src/libcore/ops/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -201,3 +201,6 @@ pub use self::generator::{Generator, GeneratorState};
201201

202202
#[unstable(feature = "coerce_unsized", issue = "27732")]
203203
pub use self::unsize::CoerceUnsized;
204+
205+
#[unstable(feature = "dispatch_from_dyn", issue = "0")]
206+
pub use self::unsize::DispatchFromDyn;

src/libcore/ops/unsize.rs

+35-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ use marker::Unsize;
4343
/// [nomicon-coerce]: ../../nomicon/coercions.html
4444
#[unstable(feature = "coerce_unsized", issue = "27732")]
4545
#[lang = "coerce_unsized"]
46-
pub trait CoerceUnsized<T> {
46+
pub trait CoerceUnsized<T: ?Sized> {
4747
// Empty.
4848
}
4949

@@ -77,3 +77,37 @@ impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut T {}
7777
// *const T -> *const U
7878
#[unstable(feature = "coerce_unsized", issue = "27732")]
7979
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
80+
81+
82+
/// This is used for object safety, to check that a method's receiver type can be dispatched on.
83+
///
84+
/// example impl:
85+
///
86+
/// ```
87+
/// # #![feature(dispatch_from_dyn, unsize)]
88+
/// # use std::{ops::DispatchFromDyn, marker::Unsize};
89+
/// # struct Rc<T: ?Sized>(::std::rc::Rc<T>);
90+
/// impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Rc<U>> for Rc<T>
91+
/// where
92+
/// T: Unsize<U>,
93+
/// {}
94+
/// ```
95+
#[unstable(feature = "dispatch_from_dyn", issue = "0")]
96+
#[cfg_attr(not(stage0), lang = "dispatch_from_dyn")]
97+
pub trait DispatchFromDyn<T> {
98+
// Empty.
99+
}
100+
101+
// &T -> &U
102+
#[unstable(feature = "dispatch_from_dyn", issue = "0")]
103+
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
104+
// &mut T -> &mut U
105+
#[unstable(feature = "dispatch_from_dyn", issue = "0")]
106+
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
107+
// *const T -> *const U
108+
#[unstable(feature = "dispatch_from_dyn", issue = "0")]
109+
impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
110+
// *mut T -> *mut U
111+
#[unstable(feature = "dispatch_from_dyn", issue = "0")]
112+
impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
113+

src/libcore/pin.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@
9191

9292
use fmt;
9393
use marker::Sized;
94-
use ops::{Deref, DerefMut, CoerceUnsized};
94+
use ops::{Deref, DerefMut, CoerceUnsized, DispatchFromDyn};
9595

9696
#[doc(inline)]
9797
pub use marker::Unpin;
@@ -324,5 +324,11 @@ where
324324
P: CoerceUnsized<U>,
325325
{}
326326

327+
#[unstable(feature = "pin", issue = "49150")]
328+
impl<'a, P, U> DispatchFromDyn<Pin<U>> for Pin<P>
329+
where
330+
P: DispatchFromDyn<U>,
331+
{}
332+
327333
#[unstable(feature = "pin", issue = "49150")]
328334
impl<P> Unpin for Pin<P> {}

src/libcore/ptr.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575

7676
use convert::From;
7777
use intrinsics;
78-
use ops::CoerceUnsized;
78+
use ops::{CoerceUnsized, DispatchFromDyn};
7979
use fmt;
8080
use hash;
8181
use marker::{PhantomData, Unsize};
@@ -2795,6 +2795,9 @@ impl<T: ?Sized> Copy for Unique<T> { }
27952795
#[unstable(feature = "ptr_internals", issue = "0")]
27962796
impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> { }
27972797

2798+
#[unstable(feature = "ptr_internals", issue = "0")]
2799+
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Unique<U>> for Unique<T> where T: Unsize<U> { }
2800+
27982801
#[unstable(feature = "ptr_internals", issue = "0")]
27992802
impl<T: ?Sized> fmt::Pointer for Unique<T> {
28002803
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -2951,6 +2954,9 @@ impl<T: ?Sized> Copy for NonNull<T> { }
29512954
#[unstable(feature = "coerce_unsized", issue = "27732")]
29522955
impl<T: ?Sized, U: ?Sized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> { }
29532956

2957+
#[unstable(feature = "dispatch_from_dyn", issue = "0")]
2958+
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NonNull<U>> for NonNull<T> where T: Unsize<U> { }
2959+
29542960
#[stable(feature = "nonnull", since = "1.25.0")]
29552961
impl<T: ?Sized> fmt::Debug for NonNull<T> {
29562962
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

src/librustc/middle/lang_items.rs

+1
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ language_item_table! {
271271
DropTraitLangItem, "drop", drop_trait, Target::Trait;
272272

273273
CoerceUnsizedTraitLangItem, "coerce_unsized", coerce_unsized_trait, Target::Trait;
274+
DispatchFromDynTraitLangItem,"dispatch_from_dyn", dispatch_from_dyn_trait, Target::Trait;
274275

275276
AddTraitLangItem, "add", add_trait, Target::Trait;
276277
SubTraitLangItem, "sub", sub_trait, Target::Trait;

src/librustc/traits/error_reporting.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
754754
}
755755

756756
ty::Predicate::ObjectSafe(trait_def_id) => {
757-
let violations = self.tcx.object_safety_violations(trait_def_id);
757+
let violations = self.tcx.global_tcx()
758+
.object_safety_violations(trait_def_id);
758759
self.tcx.report_object_safety_error(span,
759760
trait_def_id,
760761
violations)
@@ -875,7 +876,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
875876
}
876877

877878
TraitNotObjectSafe(did) => {
878-
let violations = self.tcx.object_safety_violations(did);
879+
let violations = self.tcx.global_tcx().object_safety_violations(did);
879880
self.tcx.report_object_safety_error(span, did, violations)
880881
}
881882

0 commit comments

Comments
 (0)