From 192900e7c2792b2afafb055ddba530252ce5c0a3 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Thu, 20 Sep 2018 03:18:00 -0400 Subject: Add CoerceSized impls throughout libstd This will make receiver types like `Rc` and `Pin<&mut Self>` object-safe. --- src/liballoc/boxed.rs | 5 ++++- src/liballoc/lib.rs | 1 + src/liballoc/rc.rs | 8 +++++++- src/liballoc/sync.rs | 7 ++++++- 4 files changed, 18 insertions(+), 3 deletions(-) (limited to 'src/liballoc') diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index f989e701913..8a4e646f278 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -77,7 +77,7 @@ use core::iter::FusedIterator; use core::marker::{Unpin, Unsize}; use core::mem; use core::pin::Pin; -use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState}; +use core::ops::{CoerceUnsized, CoerceSized, Deref, DerefMut, Generator, GeneratorState}; use core::ptr::{self, NonNull, Unique}; use core::task::{LocalWaker, Poll}; @@ -696,6 +696,9 @@ impl<'a, A, R> FnOnce for Box + Send + 'a> { #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U: ?Sized> CoerceUnsized> for Box {} +#[unstable(feature = "coerce_sized", issue = "0")] +impl, U: ?Sized> CoerceSized> for Box {} + #[stable(feature = "box_slice_clone", since = "1.3.0")] impl Clone for Box<[T]> { fn clone(&self) -> Self { diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 7db6261a01c..93c340a6dbd 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -86,6 +86,7 @@ #![feature(box_syntax)] #![feature(cfg_target_has_atomic)] #![feature(coerce_unsized)] +#![feature(coerce_sized)] #![feature(core_intrinsics)] #![feature(custom_attribute)] #![feature(dropck_eyepatch)] diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 3e8dfd105de..c1cc7ac976d 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -255,7 +255,7 @@ use core::marker; use core::marker::{Unpin, Unsize, PhantomData}; use core::mem::{self, align_of_val, forget, size_of_val}; use core::ops::Deref; -use core::ops::CoerceUnsized; +use core::ops::{CoerceUnsized, CoerceSized}; use core::pin::Pin; use core::ptr::{self, NonNull}; use core::convert::From; @@ -297,6 +297,9 @@ impl !marker::Sync for Rc {} #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U: ?Sized> CoerceUnsized> for Rc {} +#[unstable(feature = "coerce_sized", issue = "0")] +impl, U: ?Sized> CoerceSized> for Rc {} + impl Rc { /// Constructs a new `Rc`. /// @@ -1176,6 +1179,9 @@ impl !marker::Sync for Weak {} #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U: ?Sized> CoerceUnsized> for Weak {} +#[unstable(feature = "coerce_sized", issue = "0")] +impl, U: ?Sized> CoerceSized> for Weak {} + impl Weak { /// Constructs a new `Weak`, without allocating any memory. /// Calling [`upgrade`][Weak::upgrade] on the return value always gives [`None`]. diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index bcf5212f1ff..358e18bbe1b 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -25,7 +25,7 @@ use core::cmp::Ordering; use core::intrinsics::abort; use core::mem::{self, align_of_val, size_of_val}; use core::ops::Deref; -use core::ops::CoerceUnsized; +use core::ops::{CoerceUnsized, CoerceSized}; use core::pin::Pin; use core::ptr::{self, NonNull}; use core::marker::{Unpin, Unsize, PhantomData}; @@ -214,6 +214,9 @@ unsafe impl Sync for Arc {} #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U: ?Sized> CoerceUnsized> for Arc {} +#[unstable(feature = "coerce_sized", issue = "0")] +impl, U: ?Sized> CoerceSized> for Arc {} + /// `Weak` is a version of [`Arc`] that holds a non-owning reference to the /// managed value. The value is accessed by calling [`upgrade`] on the `Weak` /// pointer, which returns an [`Option`]`<`[`Arc`]`>`. @@ -254,6 +257,8 @@ unsafe impl Sync for Weak {} #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U: ?Sized> CoerceUnsized> for Weak {} +#[unstable(feature = "coerce_sized", issue = "0")] +impl, U: ?Sized> CoerceSized> for Weak {} #[stable(feature = "arc_weak", since = "1.4.0")] impl fmt::Debug for Weak { -- cgit 1.4.1-3-g733a5 From f12c250e40650e6103161f986f02a84b7357bdc9 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Wed, 3 Oct 2018 23:40:21 -0400 Subject: Replace CoerceSized trait with DispatchFromDyn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename `CoerceSized` to `DispatchFromDyn`, and reverse the direction so that, for example, you write ``` impl, U> DispatchFromDyn<*const U> for *const T {} ``` instead of ``` impl, U> DispatchFromDyn<*const T> for *const U {} ``` this way the trait is really just a subset of `CoerceUnsized`. The checks in object_safety.rs are updated for the new trait, and some documentation and method names in there are updated for the new trait name — e.g. `receiver_is_coercible` is now called `receiver_is_dispatchable`. Since the trait now works in the opposite direction, some code had to updated here for that too. I did not update the error messages for invalid `CoerceSized` (now `DispatchFromDyn`) implementations, except to find/replace `CoerceSized` with `DispatchFromDyn`. Will ask for suggestions in the PR thread. --- src/liballoc/boxed.rs | 6 +-- src/liballoc/lib.rs | 2 +- src/liballoc/rc.rs | 10 ++-- src/liballoc/sync.rs | 10 ++-- src/libcore/nonzero.rs | 4 +- src/libcore/ops/mod.rs | 4 +- src/libcore/ops/unsize.rs | 48 ++++++++--------- src/libcore/pin.rs | 7 ++- src/libcore/ptr.rs | 8 +-- src/librustc/middle/lang_items.rs | 2 +- src/librustc/traits/object_safety.rs | 62 +++++++++++----------- src/librustc_typeck/coherence/builtin.rs | 34 ++++++------ src/librustc_typeck/diagnostics.rs | 51 ++++++------------ .../arbitrary_self_types_pointers_and_wrappers.rs | 17 +++--- src/test/ui/invalid_coerce_sized_impls.rs | 54 ------------------- src/test/ui/invalid_coerce_sized_impls.stderr | 33 ------------ src/test/ui/invalid_dispatch_from_dyn_impls.rs | 44 +++++++++++++++ src/test/ui/invalid_dispatch_from_dyn_impls.stderr | 32 +++++++++++ 18 files changed, 201 insertions(+), 227 deletions(-) delete mode 100644 src/test/ui/invalid_coerce_sized_impls.rs delete mode 100644 src/test/ui/invalid_coerce_sized_impls.stderr create mode 100644 src/test/ui/invalid_dispatch_from_dyn_impls.rs create mode 100644 src/test/ui/invalid_dispatch_from_dyn_impls.stderr (limited to 'src/liballoc') diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 8a4e646f278..74354f605e5 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -77,7 +77,7 @@ use core::iter::FusedIterator; use core::marker::{Unpin, Unsize}; use core::mem; use core::pin::Pin; -use core::ops::{CoerceUnsized, CoerceSized, Deref, DerefMut, Generator, GeneratorState}; +use core::ops::{CoerceUnsized, DispatchFromDyn, Deref, DerefMut, Generator, GeneratorState}; use core::ptr::{self, NonNull, Unique}; use core::task::{LocalWaker, Poll}; @@ -696,8 +696,8 @@ impl<'a, A, R> FnOnce for Box + Send + 'a> { #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U: ?Sized> CoerceUnsized> for Box {} -#[unstable(feature = "coerce_sized", issue = "0")] -impl, U: ?Sized> CoerceSized> for Box {} +#[unstable(feature = "dispatch_from_dyn", issue = "0")] +impl, U: ?Sized> DispatchFromDyn> for Box {} #[stable(feature = "box_slice_clone", since = "1.3.0")] impl Clone for Box<[T]> { diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 93c340a6dbd..ad6e594c884 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -86,7 +86,7 @@ #![feature(box_syntax)] #![feature(cfg_target_has_atomic)] #![feature(coerce_unsized)] -#![feature(coerce_sized)] +#![feature(dispatch_from_dyn)] #![feature(core_intrinsics)] #![feature(custom_attribute)] #![feature(dropck_eyepatch)] diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index c1cc7ac976d..be452ebb45a 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -255,7 +255,7 @@ use core::marker; use core::marker::{Unpin, Unsize, PhantomData}; use core::mem::{self, align_of_val, forget, size_of_val}; use core::ops::Deref; -use core::ops::{CoerceUnsized, CoerceSized}; +use core::ops::{CoerceUnsized, DispatchFromDyn}; use core::pin::Pin; use core::ptr::{self, NonNull}; use core::convert::From; @@ -297,8 +297,8 @@ impl !marker::Sync for Rc {} #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U: ?Sized> CoerceUnsized> for Rc {} -#[unstable(feature = "coerce_sized", issue = "0")] -impl, U: ?Sized> CoerceSized> for Rc {} +#[unstable(feature = "dispatch_from_dyn", issue = "0")] +impl, U: ?Sized> DispatchFromDyn> for Rc {} impl Rc { /// Constructs a new `Rc`. @@ -1179,8 +1179,8 @@ impl !marker::Sync for Weak {} #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U: ?Sized> CoerceUnsized> for Weak {} -#[unstable(feature = "coerce_sized", issue = "0")] -impl, U: ?Sized> CoerceSized> for Weak {} +#[unstable(feature = "dispatch_from_dyn", issue = "0")] +impl, U: ?Sized> DispatchFromDyn> for Weak {} impl Weak { /// Constructs a new `Weak`, without allocating any memory. diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 358e18bbe1b..d388f76d8e8 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -25,7 +25,7 @@ use core::cmp::Ordering; use core::intrinsics::abort; use core::mem::{self, align_of_val, size_of_val}; use core::ops::Deref; -use core::ops::{CoerceUnsized, CoerceSized}; +use core::ops::{CoerceUnsized, DispatchFromDyn}; use core::pin::Pin; use core::ptr::{self, NonNull}; use core::marker::{Unpin, Unsize, PhantomData}; @@ -214,8 +214,8 @@ unsafe impl Sync for Arc {} #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U: ?Sized> CoerceUnsized> for Arc {} -#[unstable(feature = "coerce_sized", issue = "0")] -impl, U: ?Sized> CoerceSized> for Arc {} +#[unstable(feature = "dispatch_from_dyn", issue = "0")] +impl, U: ?Sized> DispatchFromDyn> for Arc {} /// `Weak` is a version of [`Arc`] that holds a non-owning reference to the /// managed value. The value is accessed by calling [`upgrade`] on the `Weak` @@ -257,8 +257,8 @@ unsafe impl Sync for Weak {} #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U: ?Sized> CoerceUnsized> for Weak {} -#[unstable(feature = "coerce_sized", issue = "0")] -impl, U: ?Sized> CoerceSized> for Weak {} +#[unstable(feature = "dispatch_from_dyn", issue = "0")] +impl, U: ?Sized> DispatchFromDyn> for Weak {} #[stable(feature = "arc_weak", since = "1.4.0")] impl fmt::Debug for Weak { diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 2bc6c36171c..436cd1fc057 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -10,7 +10,7 @@ //! Exposes the NonZero lang item which provides optimization hints. -use ops::{CoerceUnsized, CoerceSized}; +use ops::{CoerceUnsized, DispatchFromDyn}; /// A wrapper type for raw pointers and integers that will never be /// NULL or 0 that might allow certain optimizations. @@ -21,4 +21,4 @@ pub(crate) struct NonZero(pub(crate) T); impl, U> CoerceUnsized> for NonZero {} -impl, U: CoerceSized> CoerceSized> for NonZero {} +impl, U> DispatchFromDyn> for NonZero {} diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs index bf9775e2ae8..edfa6df11ac 100644 --- a/src/libcore/ops/mod.rs +++ b/src/libcore/ops/mod.rs @@ -202,5 +202,5 @@ pub use self::generator::{Generator, GeneratorState}; #[unstable(feature = "coerce_unsized", issue = "27732")] pub use self::unsize::CoerceUnsized; -#[unstable(feature = "coerce_sized", issue = "0")] -pub use self::unsize::CoerceSized; +#[unstable(feature = "dispatch_from_dyn", issue = "0")] +pub use self::unsize::DispatchFromDyn; diff --git a/src/libcore/ops/unsize.rs b/src/libcore/ops/unsize.rs index 0112258134d..822c80fadde 100644 --- a/src/libcore/ops/unsize.rs +++ b/src/libcore/ops/unsize.rs @@ -79,32 +79,32 @@ impl, U: ?Sized> CoerceUnsized<*const U> for *mut T {} impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} -/// Pointers to unsized types that can be coerced to a pointer to a sized type, -/// as long as pointee is actually a value of that sized type. This is used for -/// object safety, to check that a method's receiver type can be coerced from the version -/// where `Self = dyn Trait` to the version where `Self = T`, the erased, sized type -/// of the underlying object. +/// This is used for object safety, to check that a method's receiver type can be dispatched on. /// -/// `CoerceSized` is implemented for: -/// - `&[T]` is `CoerceSized<&[T; N]>` for any `N` -/// - `&Trait` is `CoerceSized<&T>` for any `T: Trait` -/// - and similarly for `&mut T`, `*const T`, `*mut T`, `Box`, `Rc`, `Arc` -#[unstable(feature = "coerce_sized", issue = "0")] -#[cfg_attr(not(stage0), lang = "coerce_sized")] -pub trait CoerceSized where T: CoerceUnsized { +/// example impl: +/// +/// ``` +/// impl DispatchFromDyn> for Rc +/// where +/// T: Unsize, +/// {} +/// ``` +#[unstable(feature = "dispatch_from_dyn", issue = "0")] +#[cfg_attr(not(stage0), lang = "dispatch_from_dyn")] +pub trait DispatchFromDyn { // Empty. } -// &U -> &T -#[unstable(feature = "coerce_sized", issue = "0")] -impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceSized<&'a T> for &'a U {} -// &mut U -> &mut T -#[unstable(feature = "coerce_sized", issue = "0")] -impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceSized<&'a mut T> for &'a mut U {} -// *const U -> *const T -#[unstable(feature = "coerce_sized", issue = "0")] -impl, U: ?Sized> CoerceSized<*const T> for *const U {} -// *mut U -> *mut T -#[unstable(feature = "coerce_sized", issue = "0")] -impl, U: ?Sized> CoerceSized<*mut T> for *mut U {} +// &T -> &U +#[unstable(feature = "dispatch_from_dyn", issue = "0")] +impl<'a, T: ?Sized+Unsize, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {} +// &mut T -> &mut U +#[unstable(feature = "dispatch_from_dyn", issue = "0")] +impl<'a, T: ?Sized+Unsize, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {} +// *const T -> *const U +#[unstable(feature = "dispatch_from_dyn", issue = "0")] +impl, U: ?Sized> DispatchFromDyn<*const U> for *const T {} +// *mut T -> *mut U +#[unstable(feature = "dispatch_from_dyn", issue = "0")] +impl, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {} diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 87ca193aeee..68de82d2945 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -91,7 +91,7 @@ use fmt; use marker::Sized; -use ops::{Deref, DerefMut, CoerceUnsized, CoerceSized}; +use ops::{Deref, DerefMut, CoerceUnsized, DispatchFromDyn}; #[doc(inline)] pub use marker::Unpin; @@ -325,10 +325,9 @@ where {} #[unstable(feature = "pin", issue = "49150")] -impl<'a, P, U> CoerceSized> for Pin +impl<'a, P, U> DispatchFromDyn> for Pin

where - P: CoerceUnsized, - U: CoerceSized

, + P: DispatchFromDyn, {} #[unstable(feature = "pin", issue = "49150")] diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 24ef028b49d..62ccf6c865c 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -75,7 +75,7 @@ use convert::From; use intrinsics; -use ops::{CoerceUnsized, CoerceSized}; +use ops::{CoerceUnsized, DispatchFromDyn}; use fmt; use hash; use marker::{PhantomData, Unsize}; @@ -2796,7 +2796,7 @@ impl Copy for Unique { } impl CoerceUnsized> for Unique where T: Unsize { } #[unstable(feature = "ptr_internals", issue = "0")] -impl CoerceSized> for Unique where T: Unsize { } +impl DispatchFromDyn> for Unique where T: Unsize { } #[unstable(feature = "ptr_internals", issue = "0")] impl fmt::Pointer for Unique { @@ -2954,8 +2954,8 @@ impl Copy for NonNull { } #[unstable(feature = "coerce_unsized", issue = "27732")] impl CoerceUnsized> for NonNull where T: Unsize { } -#[unstable(feature = "coerce_sized", issue = "0")] -impl CoerceSized> for NonNull where T: Unsize { } +#[unstable(feature = "dispatch_from_dyn", issue = "0")] +impl DispatchFromDyn> for NonNull where T: Unsize { } #[stable(feature = "nonnull", since = "1.25.0")] impl fmt::Debug for NonNull { diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 67864f67bfc..cce8081daf2 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -271,7 +271,7 @@ language_item_table! { DropTraitLangItem, "drop", drop_trait, Target::Trait; CoerceUnsizedTraitLangItem, "coerce_unsized", coerce_unsized_trait, Target::Trait; - CoerceSizedTraitLangItem, "coerce_sized", coerce_sized_trait, Target::Trait; + DispatchFromDynTraitLangItem,"dispatch_from_dyn", dispatch_from_dyn_trait, Target::Trait; AddTraitLangItem, "add", add_trait, Target::Trait; SubTraitLangItem, "sub", sub_trait, Target::Trait; diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 470a5c6bc9e..5e7a3043ae7 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -319,13 +319,12 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { &sig.map_bound(|sig| sig.inputs()[0]), ); - // until `unsized_locals` is fully implemented, `self: Self` can't be coerced from - // `Self=dyn Trait` to `Self=T`. However, this is already considered object-safe. We allow - // it as a special case here. - // FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_coercible` allows + // until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on. + // However, this is already considered object-safe. We allow it as a special case here. + // FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows // `Receiver: Unsize dyn Trait]>` if receiver_ty != self.mk_self_type() { - if !self.receiver_is_coercible(method, receiver_ty) { + if !self.receiver_is_dispatchable(method, receiver_ty) { return Some(MethodViolationCode::UncoercibleReceiver); } } @@ -333,27 +332,29 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { None } - /// checks the method's receiver (the `self` argument) can be coerced from - /// a fat pointer, including the trait object vtable, to a thin pointer. - /// e.g. from `Rc` to `Rc`, where `T` is the erased type of the underlying object. - /// More formally: + /// checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a + /// trait object. We require that `DispatchableFromDyn` be implemented for the receiver type + /// in the following way: /// - let `Receiver` be the type of the `self` argument, i.e `Self`, `&Self`, `Rc` /// - require the following bound: /// forall(T: Trait) { - /// Receiver[Self => dyn Trait]: CoerceSized T]> + /// Receiver[Self => T]: DispatchFromDyn dyn Trait]> /// } /// where `Foo[X => Y]` means "the same type as `Foo`, but with `X` replaced with `Y`" /// (substitution notation). /// /// some examples of receiver types and their required obligation - /// - `&'a mut self` requires `&'a mut dyn Trait: CoerceSized<&'a mut T>` - /// - `self: Rc` requires `Rc: CoerceSized>` + /// - `&'a mut self` requires `&'a mut T: DispatchFromDyn<&'a mut dyn Trait>` + /// - `self: Rc` requires `Rc: DispatchFromDyn>` + /// - `self: Pin>` requires `Pin>: DispatchFromDyn>>` /// - /// The only case where the receiver is not coercible, but is still a valid receiver + /// The only case where the receiver is not dispatchable, but is still a valid receiver /// type (just not object-safe), is when there is more than one level of pointer indirection. /// e.g. `self: &&Self`, `self: &Rc`, `self: Box>`. In these cases, there - /// is no way, or at least no inexpensive way, to coerce the receiver, because the object that - /// needs to be coerced is behind a pointer. + /// is no way, or at least no inexpensive way, to coerce the receiver from the version where + /// `Self = dyn Trait` to the version where `Self = T`, where `T` is the unknown erased type + /// contained by the trait object, because the object that needs to be coerced is behind + /// a pointer. /// /// In practice, there are issues with the above bound: `where` clauses that apply to `Self` /// would have to apply to `T`, trait object types have a lot of parameters that need to @@ -364,37 +365,38 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { /// /// forall (U: ?Sized) { /// if (Self: Unsize) { - /// Receiver[Self => U]: CoerceSized + /// Receiver: DispatchFromDyn U]> /// } /// } /// - /// for `self: &'a mut Self`, this means `&'a mut U: CoerceSized<&'a mut Self>` - /// for `self: Rc`, this means `Rc: CoerceSized>` + /// for `self: &'a mut Self`, this means `&'a mut Self: DispatchFromDyn<&'a mut U>` + /// for `self: Rc`, this means `Rc: DispatchFromDyn>` + /// for `self: Pin>, this means `Pin>: DispatchFromDyn>>` // // FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this // fallback query: `Receiver: Unsize U]>` to support receivers like // `self: Wrapper`. #[allow(dead_code)] - fn receiver_is_coercible( + fn receiver_is_dispatchable( self, method: &ty::AssociatedItem, receiver_ty: Ty<'tcx>, ) -> bool { - debug!("receiver_is_coercible: method = {:?}, receiver_ty = {:?}", method, receiver_ty); + debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty); let traits = (self.lang_items().unsize_trait(), - self.lang_items().coerce_sized_trait()); - let (unsize_did, coerce_sized_did) = if let (Some(u), Some(cu)) = traits { + self.lang_items().dispatch_from_dyn_trait()); + let (unsize_did, dispatch_from_dyn_did) = if let (Some(u), Some(cu)) = traits { (u, cu) } else { - debug!("receiver_is_coercible: Missing Unsize or CoerceSized traits"); + debug!("receiver_is_dispatchable: Missing Unsize or DispatchFromDyn traits"); return false; }; // use a bogus type parameter to mimick a forall(U) query using u32::MAX for now. // FIXME(mikeyhew) this is a total hack, and we should replace it when real forall queries // are implemented - let target_self_ty: Ty<'tcx> = self.mk_ty_param( + let unsized_self_ty: Ty<'tcx> = self.mk_ty_param( ::std::u32::MAX, Name::intern("RustaceansAreAwesome").as_interned_str(), ); @@ -405,7 +407,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { let predicate = ty::TraitRef { def_id: unsize_did, - substs: self.mk_substs_trait(self.mk_self_type(), &[target_self_ty.into()]), + substs: self.mk_substs_trait(self.mk_self_type(), &[unsized_self_ty.into()]), }.to_predicate(); let caller_bounds: Vec> = param_env.caller_bounds.iter().cloned() @@ -419,7 +421,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { let receiver_substs = Substs::for_item(self, method.def_id, |param, _| { if param.index == 0 { - target_self_ty.into() + unsized_self_ty.into() } else { self.mk_param_from_def(param) } @@ -427,11 +429,11 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { // the type `Receiver[Self => U]` in the query let unsized_receiver_ty = receiver_ty.subst(self, receiver_substs); - // Receiver[Self => U]: CoerceSized + // Receiver: DispatchFromDyn U]> let obligation = { let predicate = ty::TraitRef { - def_id: coerce_sized_did, - substs: self.mk_substs_trait(unsized_receiver_ty, &[receiver_ty.into()]), + def_id: dispatch_from_dyn_did, + substs: self.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]), }.to_predicate(); Obligation::new( @@ -442,7 +444,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { }; self.infer_ctxt().enter(|ref infcx| { - // the receiver is coercible iff the obligation holds + // the receiver is dispatchable iff the obligation holds infcx.predicate_must_hold(&obligation) }) } diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index eba73b1da9a..a01718bc128 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -32,7 +32,8 @@ pub fn check_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_def_id: DefId) { .check(tcx.lang_items().drop_trait(), visit_implementation_of_drop) .check(tcx.lang_items().copy_trait(), visit_implementation_of_copy) .check(tcx.lang_items().coerce_unsized_trait(), visit_implementation_of_coerce_unsized) - .check(tcx.lang_items().coerce_sized_trait(), visit_implementation_of_coerce_sized); + .check(tcx.lang_items().dispatch_from_dyn_trait(), + visit_implementation_of_dispatch_from_dyn); } struct Checker<'a, 'tcx: 'a> { @@ -162,11 +163,14 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn visit_implementation_of_coerce_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_did: DefId) { - debug!("visit_implementation_of_coerce_sized: impl_did={:?}", +fn visit_implementation_of_dispatch_from_dyn<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + impl_did: DefId, +) { + debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did); if impl_did.is_local() { - let coerce_sized_trait = tcx.lang_items().coerce_sized_trait().unwrap(); + let dispatch_from_dyn_trait = tcx.lang_items().dispatch_from_dyn_trait().unwrap(); let impl_node_id = tcx.hir.as_local_node_id(impl_did).unwrap(); let span = tcx.hir.span(impl_node_id); @@ -175,12 +179,12 @@ fn visit_implementation_of_coerce_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, i assert!(!source.has_escaping_regions()); let target = { let trait_ref = tcx.impl_trait_ref(impl_did).unwrap(); - assert_eq!(trait_ref.def_id, coerce_sized_trait); + assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait); trait_ref.substs.type_at(1) }; - debug!("visit_implementation_of_coerce_sized: {:?} -> {:?}", + debug!("visit_implementation_of_dispatch_from_dyn: {:?} -> {:?}", source, target); @@ -209,7 +213,7 @@ fn visit_implementation_of_coerce_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, i create_err( &format!( - "the trait `CoerceSized` may only be implemented \ + "the trait `DispatchFromDyn` may only be implemented \ for a coercion between structures with the same \ definition; expected {}, found {}", source_path, target_path, @@ -232,9 +236,9 @@ fn visit_implementation_of_coerce_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, i if let Ok(ok) = infcx.at(&cause, param_env).eq(ty_a, ty_b) { if ok.obligations.is_empty() { create_err( - "the trait `CoerceSized` may only be implemented for structs \ - containing the field being coerced, `PhantomData` fields, \ - and nothing else" + "the trait `DispatchFromDyn` may only be implemented \ + for structs containing the field being coerced, \ + `PhantomData` fields, and nothing else" ).note( &format!( "extra field `{}` of type `{}` is not allowed", @@ -251,15 +255,15 @@ fn visit_implementation_of_coerce_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, i if coerced_fields.is_empty() { create_err( - "the trait `CoerceSized` may only be implemented \ + "the trait `DispatchFromDyn` may only be implemented \ for a coercion between structures with a single field \ being coerced, none found" ).emit(); } else if coerced_fields.len() > 1 { create_err( - "implementing the `CoerceSized` trait requires multiple coercions", + "implementing the `DispatchFromDyn` trait requires multiple coercions", ).note( - "the trait `CoerceSized` may only be implemented \ + "the trait `DispatchFromDyn` may only be implemented \ for a coercion between structures with a single field \ being coerced" ).note( @@ -284,7 +288,7 @@ fn visit_implementation_of_coerce_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, i let predicate = tcx.predicate_for_trait_def( param_env, cause.clone(), - coerce_sized_trait, + dispatch_from_dyn_trait, 0, field.ty(tcx, substs_a), &[field.ty(tcx, substs_b).into()] @@ -311,7 +315,7 @@ fn visit_implementation_of_coerce_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, i } _ => { create_err( - "the trait `CoerceSsized` may only be implemented \ + "the trait `DispatchFromDyn` may only be implemented \ for a coercion between structures" ).emit(); } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 2cfca345c27..e53536fc55a 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -3085,75 +3085,58 @@ struct. "##, E0378: r##" -The `CoerceSized` trait currently can only be implemented for builtin pointer -types and structs that are newtype wrappers around them — that is, the struct -must have only one field (except for`PhantomData`), and that field must itself -implement `CoerceSized`. +The `DispatchFromDyn` trait currently can only be implemented for +builtin pointer types and structs that are newtype wrappers around them +— that is, the struct must have only one field (except for`PhantomData`), +and that field must itself implement `DispatchFromDyn`. Examples: ``` -#![feature(coerce_sized, unsize)] +#![feature(dispatch_from_dyn, unsize)] use std::{ marker::Unsize, - ops::CoerceSized, + ops::DispatchFromDyn, }; struct Ptr(*const T); -impl CoerceUnsized> for Ptr -where - T: Unsize, -{} - -impl CoerceSized> for Ptr +impl DispatchFromDyn> for Ptr where T: Unsize, {} ``` ``` -#![feature(coerce_unsized, coerce_sized)] -use std::ops::{CoerceUnsized, CoerceSized}; +#![feature(dispatch_from_dyn)] +use std::ops::DispatchFromDyn; struct Wrapper { ptr: T, _phantom: PhantomData<()>, } -impl CoerceUnsized> for Wrapper -where - T: CoerceUnsized, -{} - -impl CoerceSized> for Wrapper +impl DispatchFromDyn> for Wrapper where - T: CoerceUnsized, - U: CoerceSized, + T: DispatchFromDyn, {} ``` -Example of illegal CoerceSized implementation +Example of illegal `DispatchFromDyn` implementation (illegal because of extra field) ```compile-fail,E0378 -#![feature(coerce_unsized, coerce_sized)] -use std::ops::{CoerceUnsized, CoerceSized}; +#![feature(dispatch_from_dyn)] +use std::ops::DispatchFromDyn; -struct WrapperWithExtraField { +struct WrapperExtraField { ptr: T, extra_stuff: i32, } -impl CoerceUnsized> for WrapperWithExtraField -where - T: CoerceUnsized, -{} - -impl CoerceSized> for WrapperWithExtraField +impl DispatchFromDyn> for WrapperExtraField where - T: CoerceUnsized, - U: CoerceSized, + T: DispatchFromDyn, {} ``` "##, diff --git a/src/test/run-pass/arbitrary_self_types_pointers_and_wrappers.rs b/src/test/run-pass/arbitrary_self_types_pointers_and_wrappers.rs index 3abe806c9a9..e1663563cec 100644 --- a/src/test/run-pass/arbitrary_self_types_pointers_and_wrappers.rs +++ b/src/test/run-pass/arbitrary_self_types_pointers_and_wrappers.rs @@ -7,13 +7,12 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(arbitrary_self_types, unsize, coerce_unsized, coerce_sized)] +#![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)] #![feature(rustc_attrs)] use std::{ - ops::{Deref, CoerceUnsized, CoerceSized}, + ops::{Deref, CoerceUnsized, DispatchFromDyn}, marker::Unsize, - fmt::Debug, }; struct Ptr(Box); @@ -27,7 +26,7 @@ impl Deref for Ptr { } impl + ?Sized, U: ?Sized> CoerceUnsized> for Ptr {} -impl + ?Sized, U: ?Sized> CoerceSized> for Ptr {} +impl + ?Sized, U: ?Sized> DispatchFromDyn> for Ptr {} struct Wrapper(T); @@ -40,12 +39,13 @@ impl Deref for Wrapper { } impl, U> CoerceUnsized> for Wrapper {} -impl, U: CoerceSized> CoerceSized> for Wrapper {} +impl, U> DispatchFromDyn> for Wrapper {} trait Trait { - // This method can't be called on trait objects, since the receiver would be unsized, - // but should not cause an object safety error + // This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable + // without unsized_locals), but wrappers arond `Self` currently are not. + // FIXME (mikeyhew) uncomment this when unsized rvalues object-safety is implemented // fn wrapper(self: Wrapper) -> i32; fn ptr_wrapper(self: Ptr>) -> i32; fn wrapper_ptr(self: Wrapper>) -> i32; @@ -53,9 +53,6 @@ trait Trait { } impl Trait for i32 { - // fn wrapper(self: Wrapper) -> i32 { - // *self - // } fn ptr_wrapper(self: Ptr>) -> i32 { **self } diff --git a/src/test/ui/invalid_coerce_sized_impls.rs b/src/test/ui/invalid_coerce_sized_impls.rs deleted file mode 100644 index 27d65b880fa..00000000000 --- a/src/test/ui/invalid_coerce_sized_impls.rs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(unsize, coerce_sized, coerce_unsized)] - -use std::{ - ops::{CoerceSized, CoerceUnsized}, - marker::{Unsize, PhantomData}, -}; - -struct WrapperWithExtraField(T, i32); - -impl CoerceUnsized> for WrapperWithExtraField -where - T: CoerceUnsized, -{} - -impl CoerceSized> for WrapperWithExtraField -where - T: CoerceUnsized, - U: CoerceSized, -{} //~^^^^ ERROR [E0378] - - -struct MultiplePointers{ - ptr1: *const T, - ptr2: *const T, -} - -// No CoerceUnsized impl - -impl CoerceSized> for MultiplePointers -where - T: Unsize, -{} //~^^^ ERROR [E0378] - - -struct NothingToCoerce { - data: PhantomData, -} - -// No CoerceUnsized impl - -impl CoerceSized> for NothingToCoerce {} -//~^ ERROR [E0378] - -fn main() {} diff --git a/src/test/ui/invalid_coerce_sized_impls.stderr b/src/test/ui/invalid_coerce_sized_impls.stderr deleted file mode 100644 index 70fb464d426..00000000000 --- a/src/test/ui/invalid_coerce_sized_impls.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0378]: the trait `CoerceSized` may only be implemented for structs containing the field being coerced, `PhantomData` fields, and nothing else - --> $DIR/invalid_coerce_sized_impls.rs:25:1 - | -LL | / impl CoerceSized> for WrapperWithExtraField -LL | | where -LL | | T: CoerceUnsized, -LL | | U: CoerceSized, -LL | | {} //~^^^^ ERROR [E0378] - | |__^ - | - = note: extra field `1` of type `i32` is not allowed - -error[E0378]: implementing the `CoerceSized` trait requires multiple coercions - --> $DIR/invalid_coerce_sized_impls.rs:39:1 - | -LL | / impl CoerceSized> for MultiplePointers -LL | | where -LL | | T: Unsize, -LL | | {} //~^^^ ERROR [E0378] - | |__^ - | - = note: the trait `CoerceSized` may only be implemented for a coercion between structures with a single field being coerced - = note: currently, 2 fields need coercions: ptr1 (*const U to *const T), ptr2 (*const U to *const T) - -error[E0378]: the trait `CoerceSized` may only be implemented for a coercion between structures with a single field being coerced, none found - --> $DIR/invalid_coerce_sized_impls.rs:51:1 - | -LL | impl CoerceSized> for NothingToCoerce {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0378`. diff --git a/src/test/ui/invalid_dispatch_from_dyn_impls.rs b/src/test/ui/invalid_dispatch_from_dyn_impls.rs new file mode 100644 index 00000000000..101e1eb6e30 --- /dev/null +++ b/src/test/ui/invalid_dispatch_from_dyn_impls.rs @@ -0,0 +1,44 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(unsize, dispatch_from_dyn)] + +use std::{ + ops::DispatchFromDyn, + marker::{Unsize, PhantomData}, +}; + +struct WrapperWithExtraField(T, i32); + +impl DispatchFromDyn> for WrapperWithExtraField +where + T: DispatchFromDyn, +{} //~^^^ ERROR [E0378] + + +struct MultiplePointers{ + ptr1: *const T, + ptr2: *const T, +} + +impl DispatchFromDyn> for MultiplePointers +where + T: Unsize, +{} //~^^^ ERROR [E0378] + + +struct NothingToCoerce { + data: PhantomData, +} + +impl DispatchFromDyn> for NothingToCoerce {} +//~^ ERROR [E0378] + +fn main() {} diff --git a/src/test/ui/invalid_dispatch_from_dyn_impls.stderr b/src/test/ui/invalid_dispatch_from_dyn_impls.stderr new file mode 100644 index 00000000000..5e394f2fb91 --- /dev/null +++ b/src/test/ui/invalid_dispatch_from_dyn_impls.stderr @@ -0,0 +1,32 @@ +error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, `PhantomData` fields, and nothing else + --> $DIR/invalid_dispatch_from_dyn_impls.rs:20:1 + | +LL | / impl DispatchFromDyn> for WrapperWithExtraField +LL | | where +LL | | T: DispatchFromDyn, +LL | | {} //~^^^ ERROR [E0378] + | |__^ + | + = note: extra field `1` of type `i32` is not allowed + +error[E0378]: implementing the `DispatchFromDyn` trait requires multiple coercions + --> $DIR/invalid_dispatch_from_dyn_impls.rs:31:1 + | +LL | / impl DispatchFromDyn> for MultiplePointers +LL | | where +LL | | T: Unsize, +LL | | {} //~^^^ ERROR [E0378] + | |__^ + | + = note: the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced + = note: currently, 2 fields need coercions: ptr1 (*const T to *const U), ptr2 (*const T to *const U) + +error[E0378]: the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced, none found + --> $DIR/invalid_dispatch_from_dyn_impls.rs:41:1 + | +LL | impl DispatchFromDyn> for NothingToCoerce {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0378`. -- cgit 1.4.1-3-g733a5