1
Fork 0

Replace CoerceSized trait with DispatchFromDyn

Rename `CoerceSized` to `DispatchFromDyn`, and reverse the direction so that, for example, you write

```
impl<T: Unsize<U>, U> DispatchFromDyn<*const U> for *const T {}
```

instead of

```
impl<T: Unsize<U>, 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.
This commit is contained in:
Michael Hewson 2018-10-03 23:40:21 -04:00
parent c29641e067
commit f12c250e40
17 changed files with 164 additions and 190 deletions

View file

@ -77,7 +77,7 @@ use core::iter::FusedIterator;
use core::marker::{Unpin, Unsize}; use core::marker::{Unpin, Unsize};
use core::mem; use core::mem;
use core::pin::Pin; 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::ptr::{self, NonNull, Unique};
use core::task::{LocalWaker, Poll}; use core::task::{LocalWaker, Poll};
@ -696,8 +696,8 @@ impl<'a, A, R> FnOnce<A> for Box<dyn FnBox<A, Output = R> + Send + 'a> {
#[unstable(feature = "coerce_unsized", issue = "27732")] #[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Box<U>> for Box<T> {} impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Box<U>> for Box<T> {}
#[unstable(feature = "coerce_sized", issue = "0")] #[unstable(feature = "dispatch_from_dyn", issue = "0")]
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceSized<Box<T>> for Box<U> {} impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T> {}
#[stable(feature = "box_slice_clone", since = "1.3.0")] #[stable(feature = "box_slice_clone", since = "1.3.0")]
impl<T: Clone> Clone for Box<[T]> { impl<T: Clone> Clone for Box<[T]> {

View file

@ -86,7 +86,7 @@
#![feature(box_syntax)] #![feature(box_syntax)]
#![feature(cfg_target_has_atomic)] #![feature(cfg_target_has_atomic)]
#![feature(coerce_unsized)] #![feature(coerce_unsized)]
#![feature(coerce_sized)] #![feature(dispatch_from_dyn)]
#![feature(core_intrinsics)] #![feature(core_intrinsics)]
#![feature(custom_attribute)] #![feature(custom_attribute)]
#![feature(dropck_eyepatch)] #![feature(dropck_eyepatch)]

View file

@ -255,7 +255,7 @@ use core::marker;
use core::marker::{Unpin, Unsize, PhantomData}; use core::marker::{Unpin, Unsize, PhantomData};
use core::mem::{self, align_of_val, forget, size_of_val}; use core::mem::{self, align_of_val, forget, size_of_val};
use core::ops::Deref; use core::ops::Deref;
use core::ops::{CoerceUnsized, CoerceSized}; use core::ops::{CoerceUnsized, DispatchFromDyn};
use core::pin::Pin; use core::pin::Pin;
use core::ptr::{self, NonNull}; use core::ptr::{self, NonNull};
use core::convert::From; use core::convert::From;
@ -297,8 +297,8 @@ impl<T: ?Sized> !marker::Sync for Rc<T> {}
#[unstable(feature = "coerce_unsized", issue = "27732")] #[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Rc<U>> for Rc<T> {} impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Rc<U>> for Rc<T> {}
#[unstable(feature = "coerce_sized", issue = "0")] #[unstable(feature = "dispatch_from_dyn", issue = "0")]
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceSized<Rc<T>> for Rc<U> {} impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Rc<U>> for Rc<T> {}
impl<T> Rc<T> { impl<T> Rc<T> {
/// Constructs a new `Rc<T>`. /// Constructs a new `Rc<T>`.
@ -1179,8 +1179,8 @@ impl<T: ?Sized> !marker::Sync for Weak<T> {}
#[unstable(feature = "coerce_unsized", issue = "27732")] #[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Weak<U>> for Weak<T> {} impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Weak<U>> for Weak<T> {}
#[unstable(feature = "coerce_sized", issue = "0")] #[unstable(feature = "dispatch_from_dyn", issue = "0")]
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceSized<Weak<T>> for Weak<U> {} impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Weak<U>> for Weak<T> {}
impl<T> Weak<T> { impl<T> Weak<T> {
/// Constructs a new `Weak<T>`, without allocating any memory. /// Constructs a new `Weak<T>`, without allocating any memory.

View file

@ -25,7 +25,7 @@ use core::cmp::Ordering;
use core::intrinsics::abort; use core::intrinsics::abort;
use core::mem::{self, align_of_val, size_of_val}; use core::mem::{self, align_of_val, size_of_val};
use core::ops::Deref; use core::ops::Deref;
use core::ops::{CoerceUnsized, CoerceSized}; use core::ops::{CoerceUnsized, DispatchFromDyn};
use core::pin::Pin; use core::pin::Pin;
use core::ptr::{self, NonNull}; use core::ptr::{self, NonNull};
use core::marker::{Unpin, Unsize, PhantomData}; use core::marker::{Unpin, Unsize, PhantomData};
@ -214,8 +214,8 @@ unsafe impl<T: ?Sized + Sync + Send> Sync for Arc<T> {}
#[unstable(feature = "coerce_unsized", issue = "27732")] #[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Arc<U>> for Arc<T> {} impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Arc<U>> for Arc<T> {}
#[unstable(feature = "coerce_sized", issue = "0")] #[unstable(feature = "dispatch_from_dyn", issue = "0")]
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceSized<Arc<T>> for Arc<U> {} impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Arc<U>> for Arc<T> {}
/// `Weak` is a version of [`Arc`] that holds a non-owning reference to the /// `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` /// managed value. The value is accessed by calling [`upgrade`] on the `Weak`
@ -257,8 +257,8 @@ unsafe impl<T: ?Sized + Sync + Send> Sync for Weak<T> {}
#[unstable(feature = "coerce_unsized", issue = "27732")] #[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Weak<U>> for Weak<T> {} impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Weak<U>> for Weak<T> {}
#[unstable(feature = "coerce_sized", issue = "0")] #[unstable(feature = "dispatch_from_dyn", issue = "0")]
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceSized<Weak<T>> for Weak<U> {} impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Weak<U>> for Weak<T> {}
#[stable(feature = "arc_weak", since = "1.4.0")] #[stable(feature = "arc_weak", since = "1.4.0")]
impl<T: ?Sized + fmt::Debug> fmt::Debug for Weak<T> { impl<T: ?Sized + fmt::Debug> fmt::Debug for Weak<T> {

View file

@ -10,7 +10,7 @@
//! Exposes the NonZero lang item which provides optimization hints. //! 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 /// A wrapper type for raw pointers and integers that will never be
/// NULL or 0 that might allow certain optimizations. /// NULL or 0 that might allow certain optimizations.
@ -21,4 +21,4 @@ pub(crate) struct NonZero<T>(pub(crate) T);
impl<T: CoerceUnsized<U>, U> CoerceUnsized<NonZero<U>> for NonZero<T> {} impl<T: CoerceUnsized<U>, U> CoerceUnsized<NonZero<U>> for NonZero<T> {}
impl<T: CoerceUnsized<U>, U: CoerceSized<T>> CoerceSized<NonZero<T>> for NonZero<U> {} impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<NonZero<U>> for NonZero<T> {}

View file

@ -202,5 +202,5 @@ pub use self::generator::{Generator, GeneratorState};
#[unstable(feature = "coerce_unsized", issue = "27732")] #[unstable(feature = "coerce_unsized", issue = "27732")]
pub use self::unsize::CoerceUnsized; pub use self::unsize::CoerceUnsized;
#[unstable(feature = "coerce_sized", issue = "0")] #[unstable(feature = "dispatch_from_dyn", issue = "0")]
pub use self::unsize::CoerceSized; pub use self::unsize::DispatchFromDyn;

View file

@ -79,32 +79,32 @@ impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut T {}
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {} impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
/// Pointers to unsized types that can be coerced to a pointer to a sized type, /// This is used for object safety, to check that a method's receiver type can be dispatched on.
/// 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.
/// ///
/// `CoerceSized` is implemented for: /// example impl:
/// - `&[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<T>`, `Rc<T>`, `Arc<T>` /// impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Rc<U>> for Rc<T>
#[unstable(feature = "coerce_sized", issue = "0")] /// where
#[cfg_attr(not(stage0), lang = "coerce_sized")] /// T: Unsize<U>,
pub trait CoerceSized<T> where T: CoerceUnsized<Self> { /// {}
/// ```
#[unstable(feature = "dispatch_from_dyn", issue = "0")]
#[cfg_attr(not(stage0), lang = "dispatch_from_dyn")]
pub trait DispatchFromDyn<T> {
// Empty. // Empty.
} }
// &U -> &T // &T -> &U
#[unstable(feature = "coerce_sized", issue = "0")] #[unstable(feature = "dispatch_from_dyn", issue = "0")]
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceSized<&'a T> for &'a U {} impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
// &mut U -> &mut T // &mut T -> &mut U
#[unstable(feature = "coerce_sized", issue = "0")] #[unstable(feature = "dispatch_from_dyn", issue = "0")]
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceSized<&'a mut T> for &'a mut U {} impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
// *const U -> *const T // *const T -> *const U
#[unstable(feature = "coerce_sized", issue = "0")] #[unstable(feature = "dispatch_from_dyn", issue = "0")]
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceSized<*const T> for *const U {} impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
// *mut U -> *mut T // *mut T -> *mut U
#[unstable(feature = "coerce_sized", issue = "0")] #[unstable(feature = "dispatch_from_dyn", issue = "0")]
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceSized<*mut T> for *mut U {} impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}

View file

@ -91,7 +91,7 @@
use fmt; use fmt;
use marker::Sized; use marker::Sized;
use ops::{Deref, DerefMut, CoerceUnsized, CoerceSized}; use ops::{Deref, DerefMut, CoerceUnsized, DispatchFromDyn};
#[doc(inline)] #[doc(inline)]
pub use marker::Unpin; pub use marker::Unpin;
@ -325,10 +325,9 @@ where
{} {}
#[unstable(feature = "pin", issue = "49150")] #[unstable(feature = "pin", issue = "49150")]
impl<'a, P, U> CoerceSized<Pin<P>> for Pin<U> impl<'a, P, U> DispatchFromDyn<Pin<U>> for Pin<P>
where where
P: CoerceUnsized<U>, P: DispatchFromDyn<U>,
U: CoerceSized<P>,
{} {}
#[unstable(feature = "pin", issue = "49150")] #[unstable(feature = "pin", issue = "49150")]

View file

@ -75,7 +75,7 @@
use convert::From; use convert::From;
use intrinsics; use intrinsics;
use ops::{CoerceUnsized, CoerceSized}; use ops::{CoerceUnsized, DispatchFromDyn};
use fmt; use fmt;
use hash; use hash;
use marker::{PhantomData, Unsize}; use marker::{PhantomData, Unsize};
@ -2796,7 +2796,7 @@ impl<T: ?Sized> Copy for Unique<T> { }
impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> { } impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> { }
#[unstable(feature = "ptr_internals", issue = "0")] #[unstable(feature = "ptr_internals", issue = "0")]
impl<T: ?Sized, U: ?Sized> CoerceSized<Unique<T>> for Unique<U> where T: Unsize<U> { } impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Unique<U>> for Unique<T> where T: Unsize<U> { }
#[unstable(feature = "ptr_internals", issue = "0")] #[unstable(feature = "ptr_internals", issue = "0")]
impl<T: ?Sized> fmt::Pointer for Unique<T> { impl<T: ?Sized> fmt::Pointer for Unique<T> {
@ -2954,8 +2954,8 @@ impl<T: ?Sized> Copy for NonNull<T> { }
#[unstable(feature = "coerce_unsized", issue = "27732")] #[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized, U: ?Sized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> { } impl<T: ?Sized, U: ?Sized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> { }
#[unstable(feature = "coerce_sized", issue = "0")] #[unstable(feature = "dispatch_from_dyn", issue = "0")]
impl<T: ?Sized, U: ?Sized> CoerceSized<NonNull<T>> for NonNull<U> where T: Unsize<U> { } impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NonNull<U>> for NonNull<T> where T: Unsize<U> { }
#[stable(feature = "nonnull", since = "1.25.0")] #[stable(feature = "nonnull", since = "1.25.0")]
impl<T: ?Sized> fmt::Debug for NonNull<T> { impl<T: ?Sized> fmt::Debug for NonNull<T> {

View file

@ -271,7 +271,7 @@ language_item_table! {
DropTraitLangItem, "drop", drop_trait, Target::Trait; DropTraitLangItem, "drop", drop_trait, Target::Trait;
CoerceUnsizedTraitLangItem, "coerce_unsized", coerce_unsized_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; AddTraitLangItem, "add", add_trait, Target::Trait;
SubTraitLangItem, "sub", sub_trait, Target::Trait; SubTraitLangItem, "sub", sub_trait, Target::Trait;

View file

@ -319,13 +319,12 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
&sig.map_bound(|sig| sig.inputs()[0]), &sig.map_bound(|sig| sig.inputs()[0]),
); );
// until `unsized_locals` is fully implemented, `self: Self` can't be coerced from // until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on.
// `Self=dyn Trait` to `Self=T`. However, this is already considered object-safe. We allow // However, this is already considered object-safe. We allow it as a special case here.
// it as a special case here. // FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows
// FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_coercible` allows
// `Receiver: Unsize<Receiver[Self => dyn Trait]>` // `Receiver: Unsize<Receiver[Self => dyn Trait]>`
if receiver_ty != self.mk_self_type() { 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); return Some(MethodViolationCode::UncoercibleReceiver);
} }
} }
@ -333,27 +332,29 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
None None
} }
/// checks the method's receiver (the `self` argument) can be coerced from /// checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a
/// a fat pointer, including the trait object vtable, to a thin pointer. /// trait object. We require that `DispatchableFromDyn` be implemented for the receiver type
/// e.g. from `Rc<dyn Trait>` to `Rc<T>`, where `T` is the erased type of the underlying object. /// in the following way:
/// More formally:
/// - let `Receiver` be the type of the `self` argument, i.e `Self`, `&Self`, `Rc<Self>` /// - let `Receiver` be the type of the `self` argument, i.e `Self`, `&Self`, `Rc<Self>`
/// - require the following bound: /// - require the following bound:
/// forall(T: Trait) { /// forall(T: Trait) {
/// Receiver[Self => dyn Trait]: CoerceSized<Receiver[Self => T]> /// Receiver[Self => T]: DispatchFromDyn<Receiver[Self => dyn Trait]>
/// } /// }
/// where `Foo[X => Y]` means "the same type as `Foo`, but with `X` replaced with `Y`" /// where `Foo[X => Y]` means "the same type as `Foo`, but with `X` replaced with `Y`"
/// (substitution notation). /// (substitution notation).
/// ///
/// some examples of receiver types and their required obligation /// some examples of receiver types and their required obligation
/// - `&'a mut self` requires `&'a mut dyn Trait: CoerceSized<&'a mut T>` /// - `&'a mut self` requires `&'a mut T: DispatchFromDyn<&'a mut dyn Trait>`
/// - `self: Rc<Self>` requires `Rc<dyn Trait>: CoerceSized<Rc<T>>` /// - `self: Rc<Self>` requires `Rc<T>: DispatchFromDyn<Rc<dyn Trait>>`
/// - `self: Pin<Box<Self>>` requires `Pin<Box<T>>: DispatchFromDyn<Pin<Box<dyn Trait>>>`
/// ///
/// 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. /// type (just not object-safe), is when there is more than one level of pointer indirection.
/// e.g. `self: &&Self`, `self: &Rc<Self>`, `self: Box<Box<Self>>`. In these cases, there /// e.g. `self: &&Self`, `self: &Rc<Self>`, `self: Box<Box<Self>>`. In these cases, there
/// is no way, or at least no inexpensive way, to coerce the receiver, because the object that /// is no way, or at least no inexpensive way, to coerce the receiver from the version where
/// needs to be coerced is behind a pointer. /// `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` /// 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 /// 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) { /// forall (U: ?Sized) {
/// if (Self: Unsize<U>) { /// if (Self: Unsize<U>) {
/// Receiver[Self => U]: CoerceSized<Receiver> /// Receiver: DispatchFromDyn<Receiver[Self => U]>
/// } /// }
/// } /// }
/// ///
/// for `self: &'a mut Self`, this means `&'a mut U: CoerceSized<&'a mut Self>` /// for `self: &'a mut Self`, this means `&'a mut Self: DispatchFromDyn<&'a mut U>`
/// for `self: Rc<Self>`, this means `Rc<U>: CoerceSized<Rc<Self>>` /// for `self: Rc<Self>`, this means `Rc<Self>: DispatchFromDyn<Rc<U>>`
/// for `self: Pin<Box<Self>>, this means `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<U>>>`
// //
// FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this // FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this
// fallback query: `Receiver: Unsize<Receiver[Self => U]>` to support receivers like // fallback query: `Receiver: Unsize<Receiver[Self => U]>` to support receivers like
// `self: Wrapper<Self>`. // `self: Wrapper<Self>`.
#[allow(dead_code)] #[allow(dead_code)]
fn receiver_is_coercible( fn receiver_is_dispatchable(
self, self,
method: &ty::AssociatedItem, method: &ty::AssociatedItem,
receiver_ty: Ty<'tcx>, receiver_ty: Ty<'tcx>,
) -> bool { ) -> 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(), let traits = (self.lang_items().unsize_trait(),
self.lang_items().coerce_sized_trait()); self.lang_items().dispatch_from_dyn_trait());
let (unsize_did, coerce_sized_did) = if let (Some(u), Some(cu)) = traits { let (unsize_did, dispatch_from_dyn_did) = if let (Some(u), Some(cu)) = traits {
(u, cu) (u, cu)
} else { } else {
debug!("receiver_is_coercible: Missing Unsize or CoerceSized traits"); debug!("receiver_is_dispatchable: Missing Unsize or DispatchFromDyn traits");
return false; return false;
}; };
// use a bogus type parameter to mimick a forall(U) query using u32::MAX for now. // 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 // FIXME(mikeyhew) this is a total hack, and we should replace it when real forall queries
// are implemented // 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, ::std::u32::MAX,
Name::intern("RustaceansAreAwesome").as_interned_str(), Name::intern("RustaceansAreAwesome").as_interned_str(),
); );
@ -405,7 +407,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
let predicate = ty::TraitRef { let predicate = ty::TraitRef {
def_id: unsize_did, 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(); }.to_predicate();
let caller_bounds: Vec<Predicate<'tcx>> = param_env.caller_bounds.iter().cloned() let caller_bounds: Vec<Predicate<'tcx>> = 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, _| { let receiver_substs = Substs::for_item(self, method.def_id, |param, _| {
if param.index == 0 { if param.index == 0 {
target_self_ty.into() unsized_self_ty.into()
} else { } else {
self.mk_param_from_def(param) 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 // the type `Receiver[Self => U]` in the query
let unsized_receiver_ty = receiver_ty.subst(self, receiver_substs); let unsized_receiver_ty = receiver_ty.subst(self, receiver_substs);
// Receiver[Self => U]: CoerceSized<Receiver> // Receiver: DispatchFromDyn<Receiver[Self => U]>
let obligation = { let obligation = {
let predicate = ty::TraitRef { let predicate = ty::TraitRef {
def_id: coerce_sized_did, def_id: dispatch_from_dyn_did,
substs: self.mk_substs_trait(unsized_receiver_ty, &[receiver_ty.into()]), substs: self.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]),
}.to_predicate(); }.to_predicate();
Obligation::new( Obligation::new(
@ -442,7 +444,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
}; };
self.infer_ctxt().enter(|ref infcx| { 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) infcx.predicate_must_hold(&obligation)
}) })
} }

View file

@ -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().drop_trait(), visit_implementation_of_drop)
.check(tcx.lang_items().copy_trait(), visit_implementation_of_copy) .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_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> { 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) { fn visit_implementation_of_dispatch_from_dyn<'a, 'tcx>(
debug!("visit_implementation_of_coerce_sized: impl_did={:?}", tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl_did: DefId,
) {
debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}",
impl_did); impl_did);
if impl_did.is_local() { 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 impl_node_id = tcx.hir.as_local_node_id(impl_did).unwrap();
let span = tcx.hir.span(impl_node_id); 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()); assert!(!source.has_escaping_regions());
let target = { let target = {
let trait_ref = tcx.impl_trait_ref(impl_did).unwrap(); 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) trait_ref.substs.type_at(1)
}; };
debug!("visit_implementation_of_coerce_sized: {:?} -> {:?}", debug!("visit_implementation_of_dispatch_from_dyn: {:?} -> {:?}",
source, source,
target); target);
@ -209,7 +213,7 @@ fn visit_implementation_of_coerce_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, i
create_err( create_err(
&format!( &format!(
"the trait `CoerceSized` may only be implemented \ "the trait `DispatchFromDyn` may only be implemented \
for a coercion between structures with the same \ for a coercion between structures with the same \
definition; expected {}, found {}", definition; expected {}, found {}",
source_path, target_path, 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 let Ok(ok) = infcx.at(&cause, param_env).eq(ty_a, ty_b) {
if ok.obligations.is_empty() { if ok.obligations.is_empty() {
create_err( create_err(
"the trait `CoerceSized` may only be implemented for structs \ "the trait `DispatchFromDyn` may only be implemented \
containing the field being coerced, `PhantomData` fields, \ for structs containing the field being coerced, \
and nothing else" `PhantomData` fields, and nothing else"
).note( ).note(
&format!( &format!(
"extra field `{}` of type `{}` is not allowed", "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() { if coerced_fields.is_empty() {
create_err( 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 \ for a coercion between structures with a single field \
being coerced, none found" being coerced, none found"
).emit(); ).emit();
} else if coerced_fields.len() > 1 { } else if coerced_fields.len() > 1 {
create_err( create_err(
"implementing the `CoerceSized` trait requires multiple coercions", "implementing the `DispatchFromDyn` trait requires multiple coercions",
).note( ).note(
"the trait `CoerceSized` may only be implemented \ "the trait `DispatchFromDyn` may only be implemented \
for a coercion between structures with a single field \ for a coercion between structures with a single field \
being coerced" being coerced"
).note( ).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( let predicate = tcx.predicate_for_trait_def(
param_env, param_env,
cause.clone(), cause.clone(),
coerce_sized_trait, dispatch_from_dyn_trait,
0, 0,
field.ty(tcx, substs_a), field.ty(tcx, substs_a),
&[field.ty(tcx, substs_b).into()] &[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( create_err(
"the trait `CoerceSsized` may only be implemented \ "the trait `DispatchFromDyn` may only be implemented \
for a coercion between structures" for a coercion between structures"
).emit(); ).emit();
} }

View file

@ -3085,75 +3085,58 @@ struct.
"##, "##,
E0378: r##" E0378: r##"
The `CoerceSized` trait currently can only be implemented for builtin pointer The `DispatchFromDyn` trait currently can only be implemented for
types and structs that are newtype wrappers around them that is, the struct builtin pointer types and structs that are newtype wrappers around them
must have only one field (except for`PhantomData`), and that field must itself that is, the struct must have only one field (except for`PhantomData`),
implement `CoerceSized`. and that field must itself implement `DispatchFromDyn`.
Examples: Examples:
``` ```
#![feature(coerce_sized, unsize)] #![feature(dispatch_from_dyn, unsize)]
use std::{ use std::{
marker::Unsize, marker::Unsize,
ops::CoerceSized, ops::DispatchFromDyn,
}; };
struct Ptr<T: ?Sized>(*const T); struct Ptr<T: ?Sized>(*const T);
impl<T: ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Ptr<U>> for Ptr<T>
where
T: Unsize<U>,
{}
impl<T: ?Sized, U: ?Sized> CoerceSized<Ptr<T>> for Ptr<U>
where where
T: Unsize<U>, T: Unsize<U>,
{} {}
``` ```
``` ```
#![feature(coerce_unsized, coerce_sized)] #![feature(dispatch_from_dyn)]
use std::ops::{CoerceUnsized, CoerceSized}; use std::ops::DispatchFromDyn;
struct Wrapper<T> { struct Wrapper<T> {
ptr: T, ptr: T,
_phantom: PhantomData<()>, _phantom: PhantomData<()>,
} }
impl<T, U> CoerceUnsized<Wrapper<U>> for Wrapper<T> impl<T, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T>
where where
T: CoerceUnsized<U>, T: DispatchFromDyn<U>,
{}
impl<T, U> CoerceSized<Wrapper<T>> for Wrapper<U>
where
T: CoerceUnsized<U>,
U: CoerceSized<T>,
{} {}
``` ```
Example of illegal CoerceSized implementation Example of illegal `DispatchFromDyn` implementation
(illegal because of extra field) (illegal because of extra field)
```compile-fail,E0378 ```compile-fail,E0378
#![feature(coerce_unsized, coerce_sized)] #![feature(dispatch_from_dyn)]
use std::ops::{CoerceUnsized, CoerceSized}; use std::ops::DispatchFromDyn;
struct WrapperWithExtraField<T> { struct WrapperExtraField<T> {
ptr: T, ptr: T,
extra_stuff: i32, extra_stuff: i32,
} }
impl<T, U> CoerceUnsized<WrapperWithExtraField<U>> for WrapperWithExtraField<T> impl<T, U> DispatchFromDyn<WrapperExtraField<U>> for WrapperExtraField<T>
where where
T: CoerceUnsized<U>, T: DispatchFromDyn<U>,
{}
impl<T, U> CoerceSized<WrapperWithExtraField<T>> for WrapperWithExtraField<U>
where
T: CoerceUnsized<U>,
U: CoerceSized<T>,
{} {}
``` ```
"##, "##,

View file

@ -7,13 +7,12 @@
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // 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)] #![feature(rustc_attrs)]
use std::{ use std::{
ops::{Deref, CoerceUnsized, CoerceSized}, ops::{Deref, CoerceUnsized, DispatchFromDyn},
marker::Unsize, marker::Unsize,
fmt::Debug,
}; };
struct Ptr<T: ?Sized>(Box<T>); struct Ptr<T: ?Sized>(Box<T>);
@ -27,7 +26,7 @@ impl<T: ?Sized> Deref for Ptr<T> {
} }
impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {} impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {}
impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceSized<Ptr<T>> for Ptr<U> {} impl<T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<Ptr<U>> for Ptr<T> {}
struct Wrapper<T: ?Sized>(T); struct Wrapper<T: ?Sized>(T);
@ -40,12 +39,13 @@ impl<T: ?Sized> Deref for Wrapper<T> {
} }
impl<T: CoerceUnsized<U>, U> CoerceUnsized<Wrapper<U>> for Wrapper<T> {} impl<T: CoerceUnsized<U>, U> CoerceUnsized<Wrapper<U>> for Wrapper<T> {}
impl<T: CoerceUnsized<U>, U: CoerceSized<T>> CoerceSized<Wrapper<T>> for Wrapper<U> {} impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T> {}
trait Trait { trait Trait {
// This method can't be called on trait objects, since the receiver would be unsized, // This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable
// but should not cause an object safety error // 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<Self>) -> i32; // fn wrapper(self: Wrapper<Self>) -> i32;
fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32; fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32;
fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32; fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32;
@ -53,9 +53,6 @@ trait Trait {
} }
impl Trait for i32 { impl Trait for i32 {
// fn wrapper(self: Wrapper<Self>) -> i32 {
// *self
// }
fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32 { fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32 {
**self **self
} }

View file

@ -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<T, U> CoerceSized<WrapperWithExtraField<T>> for WrapperWithExtraField<U>
LL | | where
LL | | T: CoerceUnsized<U>,
LL | | U: CoerceSized<T>,
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<T: ?Sized, U: ?Sized> CoerceSized<MultiplePointers<T>> for MultiplePointers<U>
LL | | where
LL | | T: Unsize<U>,
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<T: ?Sized, U: ?Sized> CoerceSized<NothingToCoerce<U>> for NothingToCoerce<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0378`.

View file

@ -8,25 +8,19 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
#![feature(unsize, coerce_sized, coerce_unsized)] #![feature(unsize, dispatch_from_dyn)]
use std::{ use std::{
ops::{CoerceSized, CoerceUnsized}, ops::DispatchFromDyn,
marker::{Unsize, PhantomData}, marker::{Unsize, PhantomData},
}; };
struct WrapperWithExtraField<T>(T, i32); struct WrapperWithExtraField<T>(T, i32);
impl<T, U> CoerceUnsized<WrapperWithExtraField<U>> for WrapperWithExtraField<T> impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T>
where where
T: CoerceUnsized<U>, T: DispatchFromDyn<U>,
{} {} //~^^^ ERROR [E0378]
impl<T, U> CoerceSized<WrapperWithExtraField<T>> for WrapperWithExtraField<U>
where
T: CoerceUnsized<U>,
U: CoerceSized<T>,
{} //~^^^^ ERROR [E0378]
struct MultiplePointers<T: ?Sized>{ struct MultiplePointers<T: ?Sized>{
@ -34,9 +28,7 @@ struct MultiplePointers<T: ?Sized>{
ptr2: *const T, ptr2: *const T,
} }
// No CoerceUnsized impl impl<T: ?Sized, U: ?Sized> DispatchFromDyn<MultiplePointers<U>> for MultiplePointers<T>
impl<T: ?Sized, U: ?Sized> CoerceSized<MultiplePointers<T>> for MultiplePointers<U>
where where
T: Unsize<U>, T: Unsize<U>,
{} //~^^^ ERROR [E0378] {} //~^^^ ERROR [E0378]
@ -46,9 +38,7 @@ struct NothingToCoerce<T: ?Sized> {
data: PhantomData<T>, data: PhantomData<T>,
} }
// No CoerceUnsized impl impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NothingToCoerce<T>> for NothingToCoerce<U> {}
impl<T: ?Sized, U: ?Sized> CoerceSized<NothingToCoerce<U>> for NothingToCoerce<T> {}
//~^ ERROR [E0378] //~^ ERROR [E0378]
fn main() {} fn main() {}

View file

@ -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<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T>
LL | | where
LL | | T: DispatchFromDyn<U>,
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<T: ?Sized, U: ?Sized> DispatchFromDyn<MultiplePointers<U>> for MultiplePointers<T>
LL | | where
LL | | T: Unsize<U>,
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<T: ?Sized, U: ?Sized> DispatchFromDyn<NothingToCoerce<T>> for NothingToCoerce<U> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0378`.