diff options
| author | bors <bors@rust-lang.org> | 2018-11-03 02:37:29 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2018-11-03 02:37:29 +0000 |
| commit | 3fc70e8d4686190891b575204326c9b9dcd2d3ed (patch) | |
| tree | 3780984da4d2269cfcf6a71ddc54abe478fde944 /src | |
| parent | 8b096314a6381e28834ddb1e662ce90e5b32736b (diff) | |
| parent | 192e7c4b51ab35f4cfbbacde9eeffa8e12dba873 (diff) | |
| download | rust-3fc70e8d4686190891b575204326c9b9dcd2d3ed.tar.gz rust-3fc70e8d4686190891b575204326c9b9dcd2d3ed.zip | |
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
Diffstat (limited to 'src')
30 files changed, 904 insertions, 128 deletions
diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index f989e701913..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, 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,6 +696,9 @@ impl<'a, A, R> FnOnce<A> for Box<dyn FnBox<A, Output = R> + Send + 'a> { #[unstable(feature = "coerce_unsized", issue = "27732")] impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Box<U>> for Box<T> {} +#[unstable(feature = "dispatch_from_dyn", issue = "0")] +impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T> {} + #[stable(feature = "box_slice_clone", since = "1.3.0")] impl<T: Clone> Clone for Box<[T]> { fn clone(&self) -> Self { diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 7db6261a01c..ad6e594c884 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(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 3e8dfd105de..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; +use core::ops::{CoerceUnsized, DispatchFromDyn}; use core::pin::Pin; use core::ptr::{self, NonNull}; use core::convert::From; @@ -297,6 +297,9 @@ impl<T: ?Sized> !marker::Sync for Rc<T> {} #[unstable(feature = "coerce_unsized", issue = "27732")] impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Rc<U>> for Rc<T> {} +#[unstable(feature = "dispatch_from_dyn", issue = "0")] +impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Rc<U>> for Rc<T> {} + impl<T> Rc<T> { /// Constructs a new `Rc<T>`. /// @@ -1176,6 +1179,9 @@ impl<T: ?Sized> !marker::Sync for Weak<T> {} #[unstable(feature = "coerce_unsized", issue = "27732")] impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Weak<U>> for Weak<T> {} +#[unstable(feature = "dispatch_from_dyn", issue = "0")] +impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Weak<U>> for Weak<T> {} + impl<T> Weak<T> { /// Constructs a new `Weak<T>`, 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..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; +use core::ops::{CoerceUnsized, DispatchFromDyn}; use core::pin::Pin; use core::ptr::{self, NonNull}; use core::marker::{Unpin, Unsize, PhantomData}; @@ -214,6 +214,9 @@ unsafe impl<T: ?Sized + Sync + Send> Sync for Arc<T> {} #[unstable(feature = "coerce_unsized", issue = "27732")] impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Arc<U>> for Arc<T> {} +#[unstable(feature = "dispatch_from_dyn", issue = "0")] +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 /// managed value. The value is accessed by calling [`upgrade`] on the `Weak` /// pointer, which returns an [`Option`]`<`[`Arc`]`<T>>`. @@ -254,6 +257,8 @@ unsafe impl<T: ?Sized + Sync + Send> Sync for Weak<T> {} #[unstable(feature = "coerce_unsized", issue = "27732")] impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Weak<U>> for Weak<T> {} +#[unstable(feature = "dispatch_from_dyn", issue = "0")] +impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Weak<U>> for Weak<T> {} #[stable(feature = "arc_weak", since = "1.4.0")] impl<T: ?Sized + fmt::Debug> fmt::Debug for Weak<T> { diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 118e75e1ee7..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; +use ops::{CoerceUnsized, DispatchFromDyn}; /// A wrapper type for raw pointers and integers that will never be /// NULL or 0 that might allow certain optimizations. @@ -20,3 +20,5 @@ use ops::CoerceUnsized; pub(crate) struct NonZero<T>(pub(crate) T); impl<T: CoerceUnsized<U>, U> CoerceUnsized<NonZero<U>> for NonZero<T> {} + +impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<NonZero<U>> for NonZero<T> {} diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs index ce4f45762de..edfa6df11ac 100644 --- a/src/libcore/ops/mod.rs +++ b/src/libcore/ops/mod.rs @@ -201,3 +201,6 @@ pub use self::generator::{Generator, GeneratorState}; #[unstable(feature = "coerce_unsized", issue = "27732")] pub use self::unsize::CoerceUnsized; + +#[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 da72f374842..4d9a40a1b90 100644 --- a/src/libcore/ops/unsize.rs +++ b/src/libcore/ops/unsize.rs @@ -43,7 +43,7 @@ use marker::Unsize; /// [nomicon-coerce]: ../../nomicon/coercions.html #[unstable(feature = "coerce_unsized", issue = "27732")] #[lang = "coerce_unsized"] -pub trait CoerceUnsized<T> { +pub trait CoerceUnsized<T: ?Sized> { // Empty. } @@ -77,3 +77,37 @@ impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut T {} // *const T -> *const U #[unstable(feature = "coerce_unsized", issue = "27732")] impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {} + + +/// This is used for object safety, to check that a method's receiver type can be dispatched on. +/// +/// example impl: +/// +/// ``` +/// # #![feature(dispatch_from_dyn, unsize)] +/// # use std::{ops::DispatchFromDyn, marker::Unsize}; +/// # struct Rc<T: ?Sized>(::std::rc::Rc<T>); +/// impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Rc<U>> for Rc<T> +/// where +/// T: Unsize<U>, +/// {} +/// ``` +#[unstable(feature = "dispatch_from_dyn", issue = "0")] +#[cfg_attr(not(stage0), lang = "dispatch_from_dyn")] +pub trait DispatchFromDyn<T> { + // Empty. +} + +// &T -> &U +#[unstable(feature = "dispatch_from_dyn", issue = "0")] +impl<'a, T: ?Sized+Unsize<U>, 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>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {} +// *const T -> *const U +#[unstable(feature = "dispatch_from_dyn", issue = "0")] +impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {} +// *mut T -> *mut U +#[unstable(feature = "dispatch_from_dyn", issue = "0")] +impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {} + diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index a03c080fb3f..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}; +use ops::{Deref, DerefMut, CoerceUnsized, DispatchFromDyn}; #[doc(inline)] pub use marker::Unpin; @@ -325,4 +325,10 @@ where {} #[unstable(feature = "pin", issue = "49150")] +impl<'a, P, U> DispatchFromDyn<Pin<U>> for Pin<P> +where + P: DispatchFromDyn<U>, +{} + +#[unstable(feature = "pin", issue = "49150")] impl<P> Unpin for Pin<P> {} diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 36852b10fac..62ccf6c865c 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -75,7 +75,7 @@ use convert::From; use intrinsics; -use ops::CoerceUnsized; +use ops::{CoerceUnsized, DispatchFromDyn}; use fmt; use hash; use marker::{PhantomData, Unsize}; @@ -2796,6 +2796,9 @@ impl<T: ?Sized> Copy for Unique<T> { } impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> { } #[unstable(feature = "ptr_internals", issue = "0")] +impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Unique<U>> for Unique<T> where T: Unsize<U> { } + +#[unstable(feature = "ptr_internals", issue = "0")] impl<T: ?Sized> fmt::Pointer for Unique<T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Pointer::fmt(&self.as_ptr(), f) @@ -2951,6 +2954,9 @@ impl<T: ?Sized> Copy for NonNull<T> { } #[unstable(feature = "coerce_unsized", issue = "27732")] impl<T: ?Sized, U: ?Sized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> { } +#[unstable(feature = "dispatch_from_dyn", issue = "0")] +impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NonNull<U>> for NonNull<T> where T: Unsize<U> { } + #[stable(feature = "nonnull", since = "1.25.0")] impl<T: ?Sized> fmt::Debug for NonNull<T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 45de958e72e..cce8081daf2 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -271,6 +271,7 @@ language_item_table! { DropTraitLangItem, "drop", drop_trait, Target::Trait; CoerceUnsizedTraitLangItem, "coerce_unsized", coerce_unsized_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/error_reporting.rs b/src/librustc/traits/error_reporting.rs index b463faef192..18ee98c515f 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -754,7 +754,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } ty::Predicate::ObjectSafe(trait_def_id) => { - let violations = self.tcx.object_safety_violations(trait_def_id); + let violations = self.tcx.global_tcx() + .object_safety_violations(trait_def_id); self.tcx.report_object_safety_error(span, trait_def_id, violations) @@ -875,7 +876,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } TraitNotObjectSafe(did) => { - let violations = self.tcx.object_safety_violations(did); + let violations = self.tcx.global_tcx().object_safety_violations(did); self.tcx.report_object_safety_error(span, did, violations) } diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index d5942e738fd..1d76ccdca31 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -13,7 +13,8 @@ //! object if all of their methods meet certain criteria. In particular, //! they must: //! -//! - have a suitable receiver from which we can extract a vtable; +//! - have a suitable receiver from which we can extract a vtable and coerce to a "thin" version +//! that doesn't contain the vtable; //! - not reference the erased type `Self` except for in this receiver; //! - not have generic type parameters @@ -21,11 +22,12 @@ use super::elaborate_predicates; use hir::def_id::DefId; use lint; -use traits; -use ty::{self, Ty, TyCtxt, TypeFoldable}; -use ty::util::ExplicitSelf; +use traits::{self, Obligation, ObligationCause}; +use ty::{self, Ty, TyCtxt, TypeFoldable, Predicate, ToPredicate}; +use ty::subst::{Subst, Substs}; use std::borrow::Cow; -use syntax::ast; +use std::iter::{self}; +use syntax::ast::{self, Name}; use syntax_pos::Span; #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] @@ -62,8 +64,8 @@ impl ObjectSafetyViolation { format!("method `{}` references the `Self` type in where clauses", name).into(), ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) => format!("method `{}` has generic type parameters", name).into(), - ObjectSafetyViolation::Method(name, MethodViolationCode::NonStandardSelfType) => - format!("method `{}` has a non-standard `self` type", name).into(), + ObjectSafetyViolation::Method(name, MethodViolationCode::UndispatchableReceiver) => + format!("method `{}`'s receiver cannot be dispatched on", name).into(), ObjectSafetyViolation::AssociatedConst(name) => format!("the trait cannot contain associated consts like `{}`", name).into(), } @@ -85,11 +87,11 @@ pub enum MethodViolationCode { /// e.g., `fn foo<A>()` Generic, - /// arbitrary `self` type, e.g. `self: Rc<Self>` - NonStandardSelfType, + /// the method's receiver (`self` argument) can't be dispatched on + UndispatchableReceiver, } -impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { /// Returns the object safety violations that affect /// astconv - currently, Self in supertraits. This is needed @@ -113,6 +115,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn object_safety_violations(self, trait_def_id: DefId) -> Vec<ObjectSafetyViolation> { + debug!("object_safety_violations: {:?}", trait_def_id); + traits::supertrait_def_ids(self, trait_def_id) .flat_map(|def_id| self.object_safety_violations_for_trait(def_id)) .collect() @@ -277,23 +281,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { method: &ty::AssociatedItem) -> Option<MethodViolationCode> { - // The method's first parameter must be something that derefs (or - // autorefs) to `&self`. For now, we only accept `self`, `&self` - // and `Box<Self>`. + // The method's first parameter must be named `self` if !method.method_has_self_argument { return Some(MethodViolationCode::StaticMethod); } let sig = self.fn_sig(method.def_id); - let self_ty = self.mk_self_type(); - let self_arg_ty = sig.skip_binder().inputs()[0]; - if let ExplicitSelf::Other = ExplicitSelf::determine(self_arg_ty, |ty| ty == self_ty) { - return Some(MethodViolationCode::NonStandardSelfType); - } - - // The `Self` type is erased, so it should not appear in list of - // arguments or return type apart from the receiver. for input_ty in &sig.skip_binder().inputs()[1..] { if self.contains_illegal_self_type_reference(trait_def_id, input_ty) { return Some(MethodViolationCode::ReferencesSelf); @@ -320,9 +314,254 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { return Some(MethodViolationCode::WhereClauseReferencesSelf(span)); } + let receiver_ty = self.liberate_late_bound_regions( + method.def_id, + &sig.map_bound(|sig| sig.inputs()[0]), + ); + + // 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<Receiver[Self => dyn Trait]>` + if receiver_ty != self.mk_self_type() { + if !self.receiver_is_dispatchable(method, receiver_ty) { + return Some(MethodViolationCode::UndispatchableReceiver); + } else { + // sanity check to make sure the receiver actually has the layout of a pointer + + use ty::layout::Abi; + + let param_env = self.param_env(method.def_id); + + let abi_of_ty = |ty: Ty<'tcx>| -> &Abi { + match self.layout_of(param_env.and(ty)) { + Ok(layout) => &layout.abi, + Err(err) => bug!( + "Error: {}\n while computing layout for type {:?}", err, ty + ) + } + }; + + // e.g. Rc<()> + let unit_receiver_ty = self.receiver_for_self_ty( + receiver_ty, self.mk_unit(), method.def_id + ); + + match abi_of_ty(unit_receiver_ty) { + &Abi::Scalar(..) => (), + abi => bug!("Receiver when Self = () should have a Scalar ABI, found {:?}", abi) + } + + let trait_object_ty = self.object_ty_for_trait( + trait_def_id, self.mk_region(ty::ReStatic) + ); + + // e.g. Rc<dyn Trait> + let trait_object_receiver = self.receiver_for_self_ty( + receiver_ty, trait_object_ty, method.def_id + ); + + match abi_of_ty(trait_object_receiver) { + &Abi::ScalarPair(..) => (), + abi => bug!( + "Receiver when Self = {} should have a ScalarPair ABI, found {:?}", + trait_object_ty, abi + ) + } + } + } + None } + /// performs a type substitution to produce the version of receiver_ty when `Self = self_ty` + /// e.g. for receiver_ty = `Rc<Self>` and self_ty = `Foo`, returns `Rc<Foo>` + fn receiver_for_self_ty( + self, receiver_ty: Ty<'tcx>, self_ty: Ty<'tcx>, method_def_id: DefId + ) -> Ty<'tcx> { + let substs = Substs::for_item(self, method_def_id, |param, _| { + if param.index == 0 { + self_ty.into() + } else { + self.mk_param_from_def(param) + } + }); + + receiver_ty.subst(self, substs) + } + + /// creates the object type for the current trait. For example, + /// if the current trait is `Deref`, then this will be + /// `dyn Deref<Target=Self::Target> + 'static` + fn object_ty_for_trait(self, trait_def_id: DefId, lifetime: ty::Region<'tcx>) -> Ty<'tcx> { + debug!("object_ty_for_trait: trait_def_id={:?}", trait_def_id); + + let trait_ref = ty::TraitRef::identity(self, trait_def_id); + + let trait_predicate = ty::ExistentialPredicate::Trait( + ty::ExistentialTraitRef::erase_self_ty(self, trait_ref) + ); + + let mut associated_types = traits::supertraits(self, ty::Binder::dummy(trait_ref)) + .flat_map(|trait_ref| self.associated_items(trait_ref.def_id())) + .filter(|item| item.kind == ty::AssociatedKind::Type) + .collect::<Vec<_>>(); + + // existential predicates need to be in a specific order + associated_types.sort_by_key(|item| self.def_path_hash(item.def_id)); + + let projection_predicates = associated_types.into_iter().map(|item| { + ty::ExistentialPredicate::Projection(ty::ExistentialProjection { + ty: self.mk_projection(item.def_id, trait_ref.substs), + item_def_id: item.def_id, + substs: trait_ref.substs, + }) + }); + + let existential_predicates = self.mk_existential_predicates( + iter::once(trait_predicate).chain(projection_predicates) + ); + + let object_ty = self.mk_dynamic( + ty::Binder::dummy(existential_predicates), + lifetime, + ); + + debug!("object_ty_for_trait: object_ty=`{}`", object_ty); + + object_ty + } + + /// 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<Self>` + /// - require the following bound: + /// + /// Receiver[Self => T]: DispatchFromDyn<Receiver[Self => 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 Self: DispatchFromDyn<&'a mut dyn Trait>` + /// - `self: Rc<Self>` requires `Rc<Self>: DispatchFromDyn<Rc<dyn Trait>>` + /// - `self: Pin<Box<Self>>` requires `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<dyn Trait>>>` + /// + /// 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>`, `self: Box<Box<Self>>`. In these cases, there + /// 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, we cannot use `dyn Trait` explicitly in the obligation because it would result + /// in a new check that `Trait` is object safe, creating a cycle. So instead, we fudge a little + /// by introducing a new type parameter `U` such that `Self: Unsize<U>` and `U: Trait + ?Sized`, + /// and use `U` in place of `dyn Trait`. Written as a chalk-style query: + /// + /// forall (U: Trait + ?Sized) { + /// if (Self: Unsize<U>) { + /// Receiver: DispatchFromDyn<Receiver[Self => U]> + /// } + /// } + /// + /// for `self: &'a mut Self`, this means `&'a mut Self: DispatchFromDyn<&'a mut U>` + /// 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 + // fallback query: `Receiver: Unsize<Receiver[Self => U]>` to support receivers like + // `self: Wrapper<Self>`. + #[allow(dead_code)] + fn receiver_is_dispatchable( + self, + method: &ty::AssociatedItem, + receiver_ty: Ty<'tcx>, + ) -> bool { + debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty); + + let traits = (self.lang_items().unsize_trait(), + 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_dispatchable: Missing Unsize or DispatchFromDyn traits"); + return false; + }; + + // the type `U` in the query + // 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 unsized_self_ty: Ty<'tcx> = self.mk_ty_param( + ::std::u32::MAX, + Name::intern("RustaceansAreAwesome").as_interned_str(), + ); + + // `Receiver[Self => U]` + let unsized_receiver_ty = self.receiver_for_self_ty( + receiver_ty, unsized_self_ty, method.def_id + ); + + // create a modified param env, with `Self: Unsize<U>` and `U: Trait` added to caller bounds + // `U: ?Sized` is already implied here + let param_env = { + let mut param_env = self.param_env(method.def_id); + + // Self: Unsize<U> + let unsize_predicate = ty::TraitRef { + def_id: unsize_did, + substs: self.mk_substs_trait(self.mk_self_type(), &[unsized_self_ty.into()]), + }.to_predicate(); + + // U: Trait<Arg1, ..., ArgN> + let trait_predicate = { + let substs = Substs::for_item(self, method.container.assert_trait(), |param, _| { + if param.index == 0 { + unsized_self_ty.into() + } else { + self.mk_param_from_def(param) + } + }); + + ty::TraitRef { + def_id: unsize_did, + substs, + }.to_predicate() + }; + + let caller_bounds: Vec<Predicate<'tcx>> = param_env.caller_bounds.iter().cloned() + .chain(iter::once(unsize_predicate)) + .chain(iter::once(trait_predicate)) + .collect(); + + param_env.caller_bounds = self.intern_predicates(&caller_bounds); + + param_env + }; + + // Receiver: DispatchFromDyn<Receiver[Self => U]> + let obligation = { + let predicate = ty::TraitRef { + def_id: dispatch_from_dyn_did, + substs: self.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]), + }.to_predicate(); + + Obligation::new( + ObligationCause::dummy(), + param_env, + predicate, + ) + }; + + self.infer_ctxt().enter(|ref infcx| { + // the receiver is dispatchable iff the obligation holds + infcx.predicate_must_hold(&obligation) + }) + } + fn contains_illegal_self_type_reference(self, trait_def_id: DefId, ty: Ty<'tcx>) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index e2a5fdd3622..ce515c45077 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2091,18 +2091,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation.self_ty().skip_binder() ); - // Object-safety candidates are only applicable to object-safe - // traits. Including this check is useful because it helps - // inference in cases of traits like `BorrowFrom`, which are - // not object-safe, and which rely on being able to infer the - // self-type from one of the other inputs. Without this check, - // these cases wind up being considered ambiguous due to a - // (spurious) ambiguity introduced here. - let predicate_trait_ref = obligation.predicate.to_poly_trait_ref(); - if !self.tcx().is_object_safe(predicate_trait_ref.def_id()) { - return; - } - self.probe(|this, _snapshot| { // the code below doesn't care about regions, and the // self-ty here doesn't escape this probe, so just erase diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index 7c7662a88de..e50534a4e1d 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -19,7 +19,7 @@ use type_::Type; use type_of::{LayoutLlvmExt, PointerKind}; use value::Value; -use rustc_target::abi::{LayoutOf, Size, TyLayout}; +use rustc_target::abi::{LayoutOf, Size, TyLayout, Abi as LayoutAbi}; use rustc::ty::{self, Ty}; use rustc::ty::layout; @@ -302,21 +302,49 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { FnType::new_internal(cx, sig, extra_args, |ty, arg_idx| { let mut layout = cx.layout_of(ty); // Don't pass the vtable, it's not an argument of the virtual fn. - // Instead, pass just the (thin pointer) first field of `*dyn Trait`. + // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait` + // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen if arg_idx == Some(0) { - // FIXME(eddyb) `layout.field(cx, 0)` is not enough because e.g. - // `Box<dyn Trait>` has a few newtype wrappers around the raw - // pointer, so we'd have to "dig down" to find `*dyn Trait`. - let pointee = if layout.is_unsized() { - layout.ty + let fat_pointer_ty = if layout.is_unsized() { + // unsized `self` is passed as a pointer to `self` + // FIXME (mikeyhew) change this to use &own if it is ever added to the language + cx.tcx.mk_mut_ptr(layout.ty) } else { - layout.ty.builtin_deref(true) - .unwrap_or_else(|| { - bug!("FnType::new_vtable: non-pointer self {:?}", layout) - }).ty + match layout.abi { + LayoutAbi::ScalarPair(..) => (), + _ => bug!("receiver type has unsupported layout: {:?}", layout) + } + + // In the case of Rc<Self>, we need to explicitly pass a *mut RcBox<Self> + // with a Scalar (not ScalarPair) ABI. This is a hack that is understood + // elsewhere in the compiler as a method on a `dyn Trait`. + // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we + // get a built-in pointer type + let mut fat_pointer_layout = layout; + 'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr() + && !fat_pointer_layout.ty.is_region_ptr() + { + 'iter_fields: for i in 0..fat_pointer_layout.fields.count() { + let field_layout = fat_pointer_layout.field(cx, i); + + if !field_layout.is_zst() { + fat_pointer_layout = field_layout; + continue 'descend_newtypes + } + } + + bug!("receiver has no non-zero-sized fields {:?}", fat_pointer_layout); + } + + fat_pointer_layout.ty }; - let fat_ptr_ty = cx.tcx.mk_mut_ptr(pointee); - layout = cx.layout_of(fat_ptr_ty).field(cx, 0); + + // we now have a type like `*mut RcBox<dyn Trait>` + // change its layout to that of `*mut ()`, a thin pointer, but keep the same type + // this is understood as a special case elsewhere in the compiler + let unit_pointer_ty = cx.tcx.mk_mut_ptr(cx.tcx.mk_unit()); + layout = cx.layout_of(unit_pointer_ty); + layout.ty = fat_pointer_ty; } ArgType::new(layout) }) diff --git a/src/librustc_codegen_llvm/mir/block.rs b/src/librustc_codegen_llvm/mir/block.rs index d98b7869ae9..a7f4c48c89b 100644 --- a/src/librustc_codegen_llvm/mir/block.rs +++ b/src/librustc_codegen_llvm/mir/block.rs @@ -642,14 +642,46 @@ impl FunctionCx<'a, 'll, 'tcx> { (&args[..], None) }; - for (i, arg) in first_args.iter().enumerate() { + 'make_args: for (i, arg) in first_args.iter().enumerate() { let mut op = self.codegen_operand(&bx, arg); + if let (0, Some(ty::InstanceDef::Virtual(_, idx))) = (i, def) { - if let Pair(data_ptr, meta) = op.val { - llfn = Some(meth::VirtualIndex::from_index(idx) - .get_fn(&bx, meta, &fn_ty)); - llargs.push(data_ptr); - continue; + if let Pair(..) = op.val { + // In the case of Rc<Self>, we need to explicitly pass a + // *mut RcBox<Self> with a Scalar (not ScalarPair) ABI. This is a hack + // that is understood elsewhere in the compiler as a method on + // `dyn Trait`. + // To get a `*mut RcBox<Self>`, we just keep unwrapping newtypes until + // we get a value of a built-in pointer type + 'descend_newtypes: while !op.layout.ty.is_unsafe_ptr() + && !op.layout.ty.is_region_ptr() + { + 'iter_fields: for i in 0..op.layout.fields.count() { + let field = op.extract_field(&bx, i); + if !field.layout.is_zst() { + // we found the one non-zero-sized field that is allowed + // now find *its* non-zero-sized field, or stop if it's a + // pointer + op = field; + continue 'descend_newtypes + } + } + + span_bug!(span, "receiver has no non-zero-sized fields {:?}", op); + } + + // now that we have `*dyn Trait` or `&dyn Trait`, split it up into its + // data pointer and vtable. Look up the method in the vtable, and pass + // the data pointer as the first argument + match op.val { + Pair(data_ptr, meta) => { + llfn = Some(meth::VirtualIndex::from_index(idx) + .get_fn(&bx, meta, &fn_ty)); + llargs.push(data_ptr); + continue 'make_args + } + other => bug!("expected a Pair, got {:?}", other) + } } else if let Ref(data_ptr, Some(meta), _) = op.val { // by-value dynamic dispatch llfn = Some(meth::VirtualIndex::from_index(idx) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 7ddc56974d8..afd8c251b76 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1013,7 +1013,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { // most importantly, that the supertraits don't contain Self, // to avoid ICE-s. let object_safety_violations = - tcx.astconv_object_safety_violations(principal.def_id()); + tcx.global_tcx().astconv_object_safety_violations(principal.def_id()); if !object_safety_violations.is_empty() { tcx.report_object_safety_error( span, principal.def_id(), object_safety_violations) diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 05a83dd307c..99c6ba457fa 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -31,8 +31,9 @@ pub fn check_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_def_id: DefId) { Checker { tcx, trait_def_id } .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_unsized_trait(), visit_implementation_of_coerce_unsized) + .check(tcx.lang_items().dispatch_from_dyn_trait(), + visit_implementation_of_dispatch_from_dyn); } struct Checker<'a, 'tcx: 'a> { @@ -162,6 +163,174 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } +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 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); + + let source = tcx.type_of(impl_did); + assert!(!source.has_escaping_regions()); + let target = { + let trait_ref = tcx.impl_trait_ref(impl_did).unwrap(); + assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait); + + trait_ref.substs.type_at(1) + }; + + debug!("visit_implementation_of_dispatch_from_dyn: {:?} -> {:?}", + source, + target); + + let param_env = tcx.param_env(impl_did); + + let create_err = |msg: &str| { + struct_span_err!(tcx.sess, span, E0378, "{}", msg) + }; + + tcx.infer_ctxt().enter(|infcx| { + let cause = ObligationCause::misc(span, impl_node_id); + + use ty::TyKind::*; + match (&source.sty, &target.sty) { + (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b)) + if infcx.at(&cause, param_env).eq(r_a, r_b).is_ok() + && mutbl_a == *mutbl_b => (), + (&RawPtr(tm_a), &RawPtr(tm_b)) + if tm_a.mutbl == tm_b.mutbl => (), + (&Adt(def_a, substs_a), &Adt(def_b, substs_b)) + if def_a.is_struct() && def_b.is_struct() => + { + if def_a != def_b { + let source_path = tcx.item_path_str(def_a.did); + let target_path = tcx.item_path_str(def_b.did); + + create_err( + &format!( + "the trait `DispatchFromDyn` may only be implemented \ + for a coercion between structures with the same \ + definition; expected `{}`, found `{}`", + source_path, target_path, + ) + ).emit(); + + return + } + + if def_a.repr.c() || def_a.repr.packed() { + create_err( + "structs implementing `DispatchFromDyn` may not have \ + `#[repr(packed)]` or `#[repr(C)]`" + ).emit(); + } + + let fields = &def_a.non_enum_variant().fields; + + let coerced_fields = fields.iter().filter_map(|field| { + if tcx.type_of(field.did).is_phantom_data() { + // ignore PhantomData fields + return None + } + + let ty_a = field.ty(tcx, substs_a); + let ty_b = field.ty(tcx, substs_b); + if let Ok(ok) = infcx.at(&cause, param_env).eq(ty_a, ty_b) { + if ok.obligations.is_empty() { + create_err( + "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", + field.ident, ty_a, + ) + ).emit(); + + return None; + } + } + + Some(field) + }).collect::<Vec<_>>(); + + if coerced_fields.is_empty() { + create_err( + "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 `DispatchFromDyn` trait requires multiple coercions", + ).note( + "the trait `DispatchFromDyn` may only be implemented \ + for a coercion between structures with a single field \ + being coerced" + ).note( + &format!( + "currently, {} fields need coercions: {}", + coerced_fields.len(), + coerced_fields.iter().map(|field| { + format!("`{}` (`{}` to `{}`)", + field.ident, + field.ty(tcx, substs_a), + field.ty(tcx, substs_b), + ) + }).collect::<Vec<_>>() + .join(", ") + ) + ).emit(); + } else { + let mut fulfill_cx = TraitEngine::new(infcx.tcx); + + for field in coerced_fields { + + let predicate = tcx.predicate_for_trait_def( + param_env, + cause.clone(), + dispatch_from_dyn_trait, + 0, + field.ty(tcx, substs_a), + &[field.ty(tcx, substs_b).into()] + ); + + fulfill_cx.register_predicate_obligation(&infcx, predicate); + } + + // Check that all transitive obligations are satisfied. + if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) { + infcx.report_fulfillment_errors(&errors, None, false); + } + + // Finally, resolve all regions. + let region_scope_tree = region::ScopeTree::default(); + let outlives_env = OutlivesEnvironment::new(param_env); + infcx.resolve_regions_and_report_errors( + impl_did, + ®ion_scope_tree, + &outlives_env, + SuppressRegionErrors::default(), + ); + } + } + _ => { + create_err( + "the trait `DispatchFromDyn` may only be implemented \ + for a coercion between structures" + ).emit(); + } + } + }) + } +} + pub fn coerce_unsized_info<'a, 'gcx>(gcx: TyCtxt<'a, 'gcx, 'gcx>, impl_did: DefId) -> CoerceUnsizedInfo { @@ -236,7 +405,7 @@ pub fn coerce_unsized_info<'a, 'gcx>(gcx: TyCtxt<'a, 'gcx, 'gcx>, E0377, "the trait `CoerceUnsized` may only be implemented \ for a coercion between structures with the same \ - definition; expected {}, found {}", + definition; expected `{}`, found `{}`", source_path, target_path); return err_info; @@ -341,7 +510,7 @@ pub fn coerce_unsized_info<'a, 'gcx>(gcx: TyCtxt<'a, 'gcx, 'gcx>, diff_fields.len(), diff_fields.iter() .map(|&(i, a, b)| { - format!("{} ({} to {})", fields[i].ident, a, b) + format!("`{}` (`{}` to `{}`)", fields[i].ident, a, b) }) .collect::<Vec<_>>() .join(", "))); diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index f57d050fa2d..c81aea2465b 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -3084,6 +3084,66 @@ containing the unsized type is the last and only unsized type field in the struct. "##, +E0378: r##" +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(dispatch_from_dyn, unsize)] +use std::{ + marker::Unsize, + ops::DispatchFromDyn, +}; + +struct Ptr<T: ?Sized>(*const T); + +impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Ptr<U>> for Ptr<T> +where + T: Unsize<U>, +{} +``` + +``` +#![feature(dispatch_from_dyn)] +use std::{ + ops::DispatchFromDyn, + marker::PhantomData, +}; + +struct Wrapper<T> { + ptr: T, + _phantom: PhantomData<()>, +} + +impl<T, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T> +where + T: DispatchFromDyn<U>, +{} +``` + +Example of illegal `DispatchFromDyn` implementation +(illegal because of extra field) + +```compile-fail,E0378 +#![feature(dispatch_from_dyn)] +use std::ops::DispatchFromDyn; + +struct WrapperExtraField<T> { + ptr: T, + extra_stuff: i32, +} + +impl<T, U> DispatchFromDyn<WrapperExtraField<U>> for WrapperExtraField<T> +where + T: DispatchFromDyn<U>, +{} +``` +"##, + E0390: r##" You tried to implement methods for a primitive type. Erroneous code example: 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 new file mode 100644 index 00000000000..e1663563cec --- /dev/null +++ b/src/test/run-pass/arbitrary_self_types_pointers_and_wrappers.rs @@ -0,0 +1,76 @@ +// Copyright 2017 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)] +#![feature(rustc_attrs)] + +use std::{ + ops::{Deref, CoerceUnsized, DispatchFromDyn}, + marker::Unsize, +}; + +struct Ptr<T: ?Sized>(Box<T>); + +impl<T: ?Sized> Deref for Ptr<T> { + type Target = T; + + fn deref(&self) -> &T { + &*self.0 + } +} + +impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {} +impl<T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<Ptr<U>> for Ptr<T> {} + +struct Wrapper<T: ?Sized>(T); + +impl<T: ?Sized> Deref for Wrapper<T> { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } +} + +impl<T: CoerceUnsized<U>, U> CoerceUnsized<Wrapper<U>> for Wrapper<T> {} +impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T> {} + + +trait Trait { + // 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<Self>) -> i32; + fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32; + fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32; + fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32; +} + +impl Trait for i32 { + fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32 { + **self + } + fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32 { + **self + } + fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32 { + ***self + } +} + +fn main() { + let pw = Ptr(Box::new(Wrapper(5))) as Ptr<Wrapper<dyn Trait>>; + assert_eq!(pw.ptr_wrapper(), 5); + + let wp = Wrapper(Ptr(Box::new(6))) as Wrapper<Ptr<dyn Trait>>; + assert_eq!(wp.wrapper_ptr(), 6); + + let wpw = Wrapper(Ptr(Box::new(Wrapper(7)))) as Wrapper<Ptr<Wrapper<dyn Trait>>>; + assert_eq!(wpw.wrapper_ptr_wrapper(), 7); +} diff --git a/src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs b/src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs new file mode 100644 index 00000000000..80a7ce96911 --- /dev/null +++ b/src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs @@ -0,0 +1,56 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(arbitrary_self_types)] +#![feature(pin)] +#![feature(rustc_attrs)] + +use std::{ + rc::Rc, + sync::Arc, + pin::Pin, +}; + +trait Trait { + fn by_rc(self: Rc<Self>) -> i64; + fn by_arc(self: Arc<Self>) -> i64; + fn by_pin_mut(self: Pin<&mut Self>) -> i64; + fn by_pin_box(self: Pin<Box<Self>>) -> i64; +} + +impl Trait for i64 { + fn by_rc(self: Rc<Self>) -> i64 { + *self + } + fn by_arc(self: Arc<Self>) -> i64 { + *self + } + fn by_pin_mut(self: Pin<&mut Self>) -> i64 { + *self + } + fn by_pin_box(self: Pin<Box<Self>>) -> i64 { + *self + } +} + +fn main() { + let rc = Rc::new(1i64) as Rc<dyn Trait>; + assert_eq!(1, rc.by_rc()); + + let arc = Arc::new(2i64) as Arc<dyn Trait>; + assert_eq!(2, arc.by_arc()); + + let mut value = 3i64; + let pin_mut = Pin::new(&mut value) as Pin<&mut dyn Trait>; + assert_eq!(3, pin_mut.by_pin_mut()); + + let pin_box = Into::<Pin<Box<i64>>>::into(Box::new(4i64)) as Pin<Box<dyn Trait>>; + assert_eq!(4, pin_box.by_pin_box()); +} diff --git a/src/test/ui/arbitrary-self-types-not-object-safe.rs b/src/test/ui/arbitrary-self-types-not-object-safe.rs index 48918b996ef..4dc481174a4 100644 --- a/src/test/ui/arbitrary-self-types-not-object-safe.rs +++ b/src/test/ui/arbitrary-self-types-not-object-safe.rs @@ -12,38 +12,38 @@ use std::rc::Rc; trait Foo { - fn foo(self: Rc<Self>) -> usize; + fn foo(self: &Rc<Self>) -> usize; } trait Bar { - fn foo(self: Rc<Self>) -> usize where Self: Sized; - fn bar(self: Box<Self>) -> usize; + fn foo(self: &Rc<Self>) -> usize where Self: Sized; + fn bar(self: Rc<Self>) -> usize; } impl Foo for usize { - fn foo(self: Rc<Self>) -> usize { - *self + fn foo(self: &Rc<Self>) -> usize { + **self } } impl Bar for usize { - fn foo(self: Rc<Self>) -> usize { - *self + fn foo(self: &Rc<Self>) -> usize { + **self } - fn bar(self: Box<Self>) -> usize { + fn bar(self: Rc<Self>) -> usize { *self } } fn make_foo() { - let x = Box::new(5usize) as Box<Foo>; + let x = Rc::new(5usize) as Rc<Foo>; //~^ ERROR E0038 //~| ERROR E0038 } fn make_bar() { - let x = Box::new(5usize) as Box<Bar>; + let x = Rc::new(5usize) as Rc<Bar>; x.bar(); } diff --git a/src/test/ui/arbitrary-self-types-not-object-safe.stderr b/src/test/ui/arbitrary-self-types-not-object-safe.stderr index ec9e65fc4c6..77ca118471d 100644 --- a/src/test/ui/arbitrary-self-types-not-object-safe.stderr +++ b/src/test/ui/arbitrary-self-types-not-object-safe.stderr @@ -1,19 +1,19 @@ error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/arbitrary-self-types-not-object-safe.rs:40:33 + --> $DIR/arbitrary-self-types-not-object-safe.rs:40:32 | -LL | let x = Box::new(5usize) as Box<Foo>; - | ^^^^^^^^ the trait `Foo` cannot be made into an object +LL | let x = Rc::new(5usize) as Rc<Foo>; + | ^^^^^^^ the trait `Foo` cannot be made into an object | - = note: method `foo` has a non-standard `self` type + = note: method `foo`'s receiver cannot be dispatched on error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/arbitrary-self-types-not-object-safe.rs:40:13 | -LL | let x = Box::new(5usize) as Box<Foo>; - | ^^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object +LL | let x = Rc::new(5usize) as Rc<Foo>; + | ^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object | - = note: method `foo` has a non-standard `self` type - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<dyn Foo>>` for `std::boxed::Box<usize>` + = note: method `foo`'s receiver cannot be dispatched on + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::rc::Rc<dyn Foo>>` for `std::rc::Rc<usize>` error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0375.stderr b/src/test/ui/error-codes/E0375.stderr index 3ffd25084b8..f3db697790c 100644 --- a/src/test/ui/error-codes/E0375.stderr +++ b/src/test/ui/error-codes/E0375.stderr @@ -5,7 +5,7 @@ LL | impl<T, U> CoerceUnsized<Foo<U, T>> for Foo<T, U> {} | ^^^^^^^^^^^^^^^^^^^^^^^^ requires multiple coercions | = note: `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced - = note: currently, 2 fields need coercions: b (T to U), c (U to T) + = note: currently, 2 fields need coercions: `b` (`T` to `U`), `c` (`U` to `T`) error: aborting due to previous error 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..1cf5c73ab13 --- /dev/null +++ b/src/test/ui/invalid_dispatch_from_dyn_impls.rs @@ -0,0 +1,52 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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>(T, i32); + +impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T> +where + T: DispatchFromDyn<U>, +{} //~^^^ ERROR [E0378] + + +struct MultiplePointers<T: ?Sized>{ + ptr1: *const T, + ptr2: *const T, +} + +impl<T: ?Sized, U: ?Sized> DispatchFromDyn<MultiplePointers<U>> for MultiplePointers<T> +where + T: Unsize<U>, +{} //~^^^ ERROR [E0378] + + +struct NothingToCoerce<T: ?Sized> { + data: PhantomData<T>, +} + +impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NothingToCoerce<T>> for NothingToCoerce<U> {} +//~^ ERROR [E0378] + +#[repr(C)] +struct HasReprC<T: ?Sized>(Box<T>); + +impl<T: ?Sized, U: ?Sized> DispatchFromDyn<HasReprC<U>> for HasReprC<T> +where + T: Unsize<U>, +{} //~^^^ 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..82186b67d97 --- /dev/null +++ b/src/test/ui/invalid_dispatch_from_dyn_impls.stderr @@ -0,0 +1,41 @@ +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[E0378]: structs implementing `DispatchFromDyn` may not have `#[repr(packed)]` or `#[repr(C)]` + --> $DIR/invalid_dispatch_from_dyn_impls.rs:47:1 + | +LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<HasReprC<U>> for HasReprC<T> +LL | | where +LL | | T: Unsize<U>, +LL | | {} //~^^^ ERROR [E0378] + | |__^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0378`. diff --git a/src/test/ui/issues/issue-26905.stderr b/src/test/ui/issues/issue-26905.stderr index f18b58a8330..7feabef5660 100644 --- a/src/test/ui/issues/issue-26905.stderr +++ b/src/test/ui/issues/issue-26905.stderr @@ -5,7 +5,7 @@ LL | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<MyRc<U>> for MyRc<T>{ | ^^^^^^^^^^^^^^^^^^^^^^ requires multiple coercions | = note: `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced - = note: currently, 2 fields need coercions: _ptr (*const T to *const U), _boo (NotPhantomData<T> to NotPhantomData<U>) + = note: currently, 2 fields need coercions: `_ptr` (`*const T` to `*const U`), `_boo` (`NotPhantomData<T>` to `NotPhantomData<U>`) error: aborting due to previous error diff --git a/src/test/ui/traits/trait-item-privacy.rs b/src/test/ui/traits/trait-item-privacy.rs index f8e4f0d596e..1db5ec09737 100644 --- a/src/test/ui/traits/trait-item-privacy.rs +++ b/src/test/ui/traits/trait-item-privacy.rs @@ -110,9 +110,7 @@ fn check_assoc_const() { // A, B, C are resolved as inherent items, their traits don't need to be in scope C::A; //~ ERROR associated constant `A` is private //~^ ERROR the trait `assoc_const::C` cannot be made into an object - //~| ERROR the trait bound `dyn assoc_const::C: assoc_const::A` is not satisfied C::B; // ERROR the trait `assoc_const::C` cannot be made into an object - //~^ ERROR the trait bound `dyn assoc_const::C: assoc_const::B` is not satisfied C::C; // OK } diff --git a/src/test/ui/traits/trait-item-privacy.stderr b/src/test/ui/traits/trait-item-privacy.stderr index fc14ae91d7b..4ede83d5d73 100644 --- a/src/test/ui/traits/trait-item-privacy.stderr +++ b/src/test/ui/traits/trait-item-privacy.stderr @@ -100,30 +100,6 @@ error[E0624]: associated constant `A` is private LL | C::A; //~ ERROR associated constant `A` is private | ^^^^ -error[E0277]: the trait bound `dyn assoc_const::C: assoc_const::A` is not satisfied - --> $DIR/trait-item-privacy.rs:111:5 - | -LL | C::A; //~ ERROR associated constant `A` is private - | ^^^^ the trait `assoc_const::A` is not implemented for `dyn assoc_const::C` - | -note: required by `assoc_const::A::A` - --> $DIR/trait-item-privacy.rs:35:9 - | -LL | const A: u8 = 0; - | ^^^^^^^^^^^^^^^^ - -error[E0277]: the trait bound `dyn assoc_const::C: assoc_const::B` is not satisfied - --> $DIR/trait-item-privacy.rs:114:5 - | -LL | C::B; // ERROR the trait `assoc_const::C` cannot be made into an object - | ^^^^ the trait `assoc_const::B` is not implemented for `dyn assoc_const::C` - | -note: required by `assoc_const::B::B` - --> $DIR/trait-item-privacy.rs:39:9 - | -LL | const B: u8 = 0; - | ^^^^^^^^^^^^^^^^ - error[E0038]: the trait `assoc_const::C` cannot be made into an object --> $DIR/trait-item-privacy.rs:111:5 | @@ -135,36 +111,36 @@ LL | C::A; //~ ERROR associated constant `A` is private = note: the trait cannot contain associated consts like `A` error[E0223]: ambiguous associated type - --> $DIR/trait-item-privacy.rs:127:12 + --> $DIR/trait-item-privacy.rs:125:12 | LL | let _: S::A; //~ ERROR ambiguous associated type | ^^^^ help: use fully-qualified syntax: `<S as Trait>::A` error[E0223]: ambiguous associated type - --> $DIR/trait-item-privacy.rs:128:12 + --> $DIR/trait-item-privacy.rs:126:12 | LL | let _: S::B; //~ ERROR ambiguous associated type | ^^^^ help: use fully-qualified syntax: `<S as Trait>::B` error[E0223]: ambiguous associated type - --> $DIR/trait-item-privacy.rs:129:12 + --> $DIR/trait-item-privacy.rs:127:12 | LL | let _: S::C; //~ ERROR ambiguous associated type | ^^^^ help: use fully-qualified syntax: `<S as Trait>::C` error: associated type `A` is private - --> $DIR/trait-item-privacy.rs:131:12 + --> $DIR/trait-item-privacy.rs:129:12 | LL | let _: T::A; //~ ERROR associated type `A` is private | ^^^^ error: associated type `A` is private - --> $DIR/trait-item-privacy.rs:140:9 + --> $DIR/trait-item-privacy.rs:138:9 | LL | A = u8, //~ ERROR associated type `A` is private | ^^^^^^ -error: aborting due to 17 previous errors +error: aborting due to 15 previous errors -Some errors occurred: E0038, E0223, E0277, E0599, E0624. +Some errors occurred: E0038, E0223, E0599, E0624. For more information about an error, try `rustc --explain E0038`. diff --git a/src/test/ui/traits/trait-test-2.rs b/src/test/ui/traits/trait-test-2.rs index dac76fb57fd..01d7e89847a 100644 --- a/src/test/ui/traits/trait-test-2.rs +++ b/src/test/ui/traits/trait-test-2.rs @@ -20,5 +20,4 @@ fn main() { (box 10 as Box<bar>).dup(); //~^ ERROR E0038 //~| ERROR E0038 - //~| ERROR E0277 } diff --git a/src/test/ui/traits/trait-test-2.stderr b/src/test/ui/traits/trait-test-2.stderr index 1e1fcbe340e..db0cd38cb6a 100644 --- a/src/test/ui/traits/trait-test-2.stderr +++ b/src/test/ui/traits/trait-test-2.stderr @@ -10,12 +10,6 @@ error[E0107]: wrong number of type arguments: expected 1, found 2 LL | 10.blah::<i32, i32>(); //~ ERROR wrong number of type arguments: expected 1, found 2 | ^^^ unexpected type argument -error[E0277]: the trait bound `dyn bar: bar` is not satisfied - --> $DIR/trait-test-2.rs:20:26 - | -LL | (box 10 as Box<bar>).dup(); - | ^^^ the trait `bar` is not implemented for `dyn bar` - error[E0038]: the trait `bar` cannot be made into an object --> $DIR/trait-test-2.rs:20:16 | @@ -35,7 +29,7 @@ LL | (box 10 as Box<bar>).dup(); = note: method `blah` has generic type parameters = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<dyn bar>>` for `std::boxed::Box<{integer}>` -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors -Some errors occurred: E0038, E0107, E0277. +Some errors occurred: E0038, E0107. For more information about an error, try `rustc --explain E0038`. |
