diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index c25f3eb8f1750..be70ed9191c41 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -66,7 +66,7 @@ use core::iter::FusedIterator; use core::marker::{Unpin, Unsize}; use core::mem; use core::pin::PinMut; -use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState}; +use core::ops::{CoerceUnsized, CoerceSized, Deref, DerefMut, Generator, GeneratorState}; use core::ptr::{self, NonNull, Unique}; use core::task::{Context, Poll, Spawn, SpawnErrorKind, SpawnObjError}; @@ -670,6 +670,9 @@ impl<'a, A, R> FnOnce for Box + Send + 'a> { #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U: ?Sized> CoerceUnsized> for Box {} +#[unstable(feature = "coerce_sized", issue = "0")] +impl, U: ?Sized> CoerceSized> for Box {} + #[stable(feature = "box_slice_clone", since = "1.3.0")] impl Clone for Box<[T]> { fn clone(&self) -> Self { diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 452d2b1472ff4..61b86cb40a0c3 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -88,6 +88,7 @@ #![feature(box_syntax)] #![feature(cfg_target_has_atomic)] #![feature(coerce_unsized)] +#![feature(coerce_sized)] #![cfg_attr(stage0, feature(const_fn))] #![cfg_attr(not(stage0), feature(min_const_fn))] #![feature(core_intrinsics)] diff --git a/src/liballoc/pin.rs b/src/liballoc/pin.rs index 17bbc9882d976..51b1111a67b39 100644 --- a/src/liballoc/pin.rs +++ b/src/liballoc/pin.rs @@ -92,7 +92,7 @@ use core::convert::From; use core::fmt; use core::future::{Future, FutureObj, LocalFutureObj, UnsafeFutureObj}; use core::marker::Unsize; -use core::ops::{CoerceUnsized, Deref, DerefMut}; +use core::ops::{CoerceUnsized, CoerceSized, Deref, DerefMut}; use core::task::{Context, Poll}; use boxed::Box; @@ -256,6 +256,11 @@ impl fmt::Pointer for PinBox { #[unstable(feature = "pin", issue = "49150")] impl, U: ?Sized> CoerceUnsized> for PinBox {} +#[unstable(feature = "coerce_sized", issue = "0")] +impl, U: ?Sized> CoerceSized> for PinBox {} + + + #[unstable(feature = "pin", issue = "49150")] impl Unpin for PinBox {} diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 4860daa11e20c..4ab65fde9b79e 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -255,7 +255,7 @@ use core::marker; use core::marker::{Unsize, PhantomData}; use core::mem::{self, align_of_val, forget, size_of_val}; use core::ops::Deref; -use core::ops::CoerceUnsized; +use core::ops::{CoerceUnsized, CoerceSized}; use core::ptr::{self, NonNull}; use core::convert::From; use core::usize; @@ -295,6 +295,9 @@ impl !marker::Sync for Rc {} #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U: ?Sized> CoerceUnsized> for Rc {} +#[unstable(feature = "coerce_sized", issue = "0")] +impl, U: ?Sized> CoerceSized> for Rc {} + impl Rc { /// Constructs a new `Rc`. /// @@ -1171,6 +1174,9 @@ impl !marker::Sync for Weak {} #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U: ?Sized> CoerceUnsized> for Weak {} +#[unstable(feature = "coerce_sized", issue = "0")] +impl, U: ?Sized> CoerceSized> for Weak {} + impl Weak { /// Constructs a new `Weak`, without allocating any memory. /// Calling [`upgrade`] on the return value always gives [`None`]. diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index db7a4044b267f..36a1db833cfc0 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -25,7 +25,7 @@ use core::cmp::Ordering; use core::intrinsics::abort; use core::mem::{self, align_of_val, size_of_val}; use core::ops::Deref; -use core::ops::CoerceUnsized; +use core::ops::{CoerceUnsized, CoerceSized}; use core::ptr::{self, NonNull}; use core::marker::{Unsize, PhantomData}; use core::hash::{Hash, Hasher}; @@ -212,6 +212,9 @@ unsafe impl Sync for Arc {} #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U: ?Sized> CoerceUnsized> for Arc {} +#[unstable(feature = "coerce_sized", issue = "0")] +impl, U: ?Sized> CoerceSized> for Arc {} + /// `Weak` is a version of [`Arc`] that holds a non-owning reference to the /// managed value. The value is accessed by calling [`upgrade`] on the `Weak` /// pointer, which returns an [`Option`]`<`[`Arc`]`>`. @@ -252,6 +255,8 @@ unsafe impl Sync for Weak {} #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U: ?Sized> CoerceUnsized> for Weak {} +#[unstable(feature = "coerce_sized", issue = "0")] +impl, U: ?Sized> CoerceSized> for Weak {} #[stable(feature = "arc_weak", since = "1.4.0")] impl fmt::Debug for Weak { diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs index ce4f45762de48..bf9775e2ae813 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 = "coerce_sized", issue = "0")] +pub use self::unsize::CoerceSized; diff --git a/src/libcore/ops/unsize.rs b/src/libcore/ops/unsize.rs index da72f3748425d..4faace26b02f9 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 { +pub trait CoerceUnsized { // Empty. } @@ -77,3 +77,34 @@ impl, U: ?Sized> CoerceUnsized<*const U> for *mut T {} // *const T -> *const U #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} + + +/// Pointers to unsized types that can be coerced to a pointer to a sized type, +/// as long as pointee is actually a value of that sized type. This is used for +/// object safety, to check that a method's receiver type can be coerced from the version +/// where `Self = dyn Trait` to the version where `Self = T`, the erased, sized type +/// of the underlying object. +/// +/// CoerceSized is implemented for: +/// - &[T] is CoerceSized<&[T; N]> for any N +/// - &Trait is CoerceSized<&T> for any T: Trait +/// - and similarly for &mut T, *const T, *mut T, Box, Rc, Arc +#[unstable(feature = "coerce_sized", issue = "0")] +#[cfg_attr(not(stage0), lang = "coerce_sized")] +pub trait CoerceSized where T: CoerceUnsized { + // Empty. +} + +// &U -> &T +#[unstable(feature = "coerce_sized", issue = "0")] +impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceSized<&'a T> for &'a U {} +// &mut U -> &mut T +#[unstable(feature = "coerce_sized", issue = "0")] +impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceSized<&'a mut T> for &'a mut U {} +// *const U -> *const T +#[unstable(feature = "coerce_sized", issue = "0")] +impl, U: ?Sized> CoerceSized<*const T> for *const U {} +// *mut U -> *mut T +#[unstable(feature = "coerce_sized", issue = "0")] +impl, U: ?Sized> CoerceSized<*mut T> for *mut U {} + diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index e9001f86b3526..f05bc59178284 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -10,7 +10,7 @@ use fmt; use future::{Future, UnsafeFutureObj}; use marker::{Sized, Unpin, Unsize}; use task::{Context, Poll}; -use ops::{Deref, DerefMut, CoerceUnsized}; +use ops::{Deref, DerefMut, CoerceUnsized, CoerceSized}; /// A pinned reference. /// @@ -141,6 +141,9 @@ impl<'a, T: ?Sized> fmt::Pointer for PinMut<'a, T> { #[unstable(feature = "pin", issue = "49150")] impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized> for PinMut<'a, T> {} +#[unstable(feature = "pin", issue = "49150")] +impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceSized> for PinMut<'a, U> {} + #[unstable(feature = "pin", issue = "49150")] impl<'a, T: ?Sized> Unpin for PinMut<'a, T> {} diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index d92f856fa4dbf..d49b44b27b3da 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -252,6 +252,7 @@ language_item_table! { DropTraitLangItem, "drop", drop_trait; CoerceUnsizedTraitLangItem, "coerce_unsized", coerce_unsized_trait; + CoerceSizedTraitLangItem, "coerce_sized", coerce_sized_trait; AddTraitLangItem, "add", add_trait; SubTraitLangItem, "sub", sub_trait; diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index b34378151ccb3..f43be0aa87b6c 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -708,7 +708,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) @@ -835,7 +836,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 17d55b77625b2..f6e37fae69d5f 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::UncoercibleReceiver) => + format!("method `{}` has an uncoercible receiver type", 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()` Generic, - /// arbitrary `self` type, e.g. `self: Rc` - NonStandardSelfType, + /// the self argument can't be coerced from Self=dyn Trait to Self=T where T: Trait + UncoercibleReceiver, } -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 { + 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 { - // The method's first parameter must be something that derefs (or - // autorefs) to `&self`. For now, we only accept `self`, `&self` - // and `Box`. + // 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,134 @@ 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 we get by-value DST, `self: Self` can't be coerced + // but we allow this as a special case. + // maybe instead we should also check for + // for (U) { if (Self: Unsize) { Receiver: Unsize>}} + if receiver_ty != self.mk_self_type() { + if !self.receiver_is_coercible(method, receiver_ty) { + return Some(MethodViolationCode::UncoercibleReceiver); + } + } + None } + /// checks the method's receiver (the `self` argument) can be coerced from + /// a fat pointer, including the trait object vtable, to a thin pointer. + /// e.g. from `Rc` to `Rc`, where `T` is the erased type of the underlying object. + /// More formally: + /// - let `Receiver` be the type of the `self` argument, i.e `Self`, `&Self`, `Rc` + /// - require the following bound: + /// forall(T: Trait) { + /// Receiver[Self => dyn Trait]: CoerceSized T]> + /// } + /// 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 + /// - `self` requires `dyn Trait: CoerceSized` + /// - `&'a mut self` requires `&'a mut dyn Trait: CoerceSized<&'a mut T>` + /// - `self: Rc` requires `Rc: CoerceSized>` + /// + /// The only case where the receiver is not coercible, but is still a valid receiver + /// type (just not object-safe), is when there is more than one level of pointer indirection. + /// e.g. `self: &&Self`, `self: &Rc`, `self: Box>`. In these cases, there + /// is no way, or at least no inexpensive way, to coerce the receiver, because the object that + /// needs to be coerced is behind a pointer. + /// + /// In practice, there are issues with the above bound: `where` clauses that apply to `Self` + /// would have to apply to `T`, and trait object types have a lot of parameters that need to + /// be filled in (lifetime and type parameters, and the lifetime of the actual object). So in + /// the implementation, we use the following, more general bound: + /// forall (U: ?Sized) { + /// if (Self: Unsize) { + /// Receiver[Self => U]: CoerceSized + /// } + /// } + /// + /// for `self: Self`, this means `U: CoerceSized` + /// for `self: &'a mut Self`, this means `&'a mut U: CoerceSized<&'a mut Self>` + /// for `self: Rc`, this means `Rc: CoerceSized>` + #[allow(dead_code)] + fn receiver_is_coercible( + self, + method: &ty::AssociatedItem, + receiver_ty: Ty<'tcx>, + ) -> bool { + debug!("receiver_is_coercible: method = {:?}, receiver_ty = {:?}", method, receiver_ty); + + let traits = (self.lang_items().unsize_trait(), + self.lang_items().coerce_sized_trait()); + let (unsize_did, coerce_sized_did) = if let (Some(u), Some(cu)) = traits { + (u, cu) + } else { + debug!("receiver_is_coercible: Missing Unsize or CoerceSized traits"); + return false; + }; + + // use a bogus type parameter to mimick a forall(U) query + // using u32::MAX for now. This is a hack that will be replaced when we have real forall + // queries + let target_self_ty: Ty<'tcx> = self.mk_ty_param( + ::std::u32::MAX, + Name::intern("RustaceansAreAwesome").as_interned_str(), + ); + + // create a modified param env, with + // `Self: Unsize` added to the caller bounds + let param_env = { + let mut param_env = self.param_env(method.def_id); + + let predicate = ty::TraitRef { + def_id: unsize_did, + substs: self.mk_substs_trait(self.mk_self_type(), &[target_self_ty.into()]), + }.to_predicate(); + + let caller_bounds: Vec> = param_env.caller_bounds.iter().cloned() + .chain(iter::once(predicate)) + .collect(); + + param_env.caller_bounds = self.intern_predicates(&caller_bounds); + + param_env + }; + + let receiver_substs = Substs::for_item(self, method.def_id, |param, _| { + if param.index == 0 { + target_self_ty.into() + } else { + self.mk_param_from_def(param) + } + }); + // the type `Receiver[Self => U]` in the query + let unsized_receiver_ty = receiver_ty.subst(self, receiver_substs); + + // Receiver[Self => U]: CoerceSized + let obligation = { + let predicate = ty::TraitRef { + def_id: coerce_sized_did, + substs: self.mk_substs_trait(unsized_receiver_ty, &[receiver_ty.into()]), + }.to_predicate(); + + Obligation::new( + ObligationCause::dummy(), + param_env, + predicate, + ) + }; + + self.infer_ctxt().enter(|ref infcx| { + // the receiver is coercible 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 69bdeec6eea23..10e2a9d478b07 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1853,18 +1853,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { debug!("assemble_candidates_from_object_ty(self_ty={:?})", 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 @@ -1885,6 +1873,17 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } } ty::Infer(ty::TyVar(_)) => { + // 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 !this.tcx().is_object_safe(predicate_trait_ref.def_id()) { + return; + } debug!("assemble_candidates_from_object_ty: ambiguous"); candidates.ambiguous = true; // could wind up being an object type return; diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index 684f2b358858f..2928717c94ffe 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -316,7 +316,11 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { // pointer, so we'd have to "dig down" to find `*dyn Trait`. let pointee = layout.ty.builtin_deref(true) .unwrap_or_else(|| { - bug!("FnType::new_vtable: non-pointer self {:?}", layout) + // builtin_deref only works for basic pointer types, + // i.e. &Self, *const Self, Box + // If it fails, then this is a custom receiver like Rc + unimplemented!("dynamic dispatch on custom receivers is not \ + yet implemented in #![feature(arbitrary_self_types)]"); }).ty; let fat_ptr_ty = cx.tcx.mk_mut_ptr(pointee); layout = cx.layout_of(fat_ptr_ty).field(cx, 0); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 804aad3c0ecce..74525273bef9d 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -988,7 +988,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/test/compile-fail/arbitrary-self-types-stdlib-pointers.rs b/src/test/compile-fail/arbitrary-self-types-stdlib-pointers.rs new file mode 100644 index 0000000000000..cfdd4192755c6 --- /dev/null +++ b/src/test/compile-fail/arbitrary-self-types-stdlib-pointers.rs @@ -0,0 +1,58 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(arbitrary_self_types)] +#![feature(pin)] +#![feature(rustc_attrs)] + +use std::{ + rc::Rc, + sync::Arc, + pin::{PinMut, PinBox}, +}; + +trait Trait { + fn by_rc(self: Rc) -> i64; + fn by_arc(self: Arc) -> i64; + fn by_pin_mut(self: PinMut) -> i64; + fn by_pin_box(self: PinBox) -> i64; +} + +impl Trait for i64 { + fn by_rc(self: Rc) -> i64 { + *self + } + fn by_arc(self: Arc) -> i64 { + *self + } + fn by_pin_mut(self: PinMut) -> i64 { + *self + } + fn by_pin_box(self: PinBox) -> i64 { + *self + } +} + + +#[rustc_error] +fn main() { //~ ERROR compilation successful + let rc = Rc::new(1i64) as Rc; + assert_eq!(1, rc.by_rc()); + + let arc = Arc::new(2i64) as Arc; + assert_eq!(2, arc.by_arc()); + + let mut value = 3i64; + let pin_mut = PinMut::new(&mut value) as PinMut; + assert_eq!(3, pin_mut.by_pin_mut()); + + let pin_box = PinBox::new(4i64) as PinBox; + assert_eq!(4, pin_box.by_pin_box()); +} diff --git a/src/test/compile-fail/arbitrary_self_types_pointers_and_wrappers.rs b/src/test/compile-fail/arbitrary_self_types_pointers_and_wrappers.rs new file mode 100644 index 0000000000000..ed81bcef070a1 --- /dev/null +++ b/src/test/compile-fail/arbitrary_self_types_pointers_and_wrappers.rs @@ -0,0 +1,80 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![feature(arbitrary_self_types, unsize, coerce_unsized, coerce_sized)] +#![feature(rustc_attrs)] + +use std::{ + ops::{Deref, CoerceUnsized, CoerceSized}, + marker::Unsize, + fmt::Debug, +}; + +struct Ptr(Box); + +impl Deref for Ptr { + type Target = T; + + fn deref(&self) -> &T { + &*self.0 + } +} + +impl + ?Sized, U: ?Sized> CoerceUnsized> for Ptr {} +impl + ?Sized, U: ?Sized> CoerceSized> for Ptr {} + +struct Wrapper(T); + +impl Deref for Wrapper { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } +} + +impl, U> CoerceUnsized> for Wrapper {} +impl, U: CoerceSized> CoerceSized> for Wrapper {} + + +trait Trait { + // This method can't be called on trait objects, since the receiver would be unsized, + // but should not cause an object safety error + // fn wrapper(self: Wrapper) -> i32; + fn ptr_wrapper(self: Ptr>) -> i32; + fn wrapper_ptr(self: Wrapper>) -> i32; + fn wrapper_ptr_wrapper(self: Wrapper>>) -> i32; +} + +impl Trait for i32 { + // fn wrapper(self: Wrapper) -> i32 { + // *self + // } + fn ptr_wrapper(self: Ptr>) -> i32 { + **self + } + fn wrapper_ptr(self: Wrapper>) -> i32 { + **self + } + fn wrapper_ptr_wrapper(self: Wrapper>>) -> i32 { + ***self + } +} + +#[rustc_error] +fn main() { //~ ERROR compilation successful + let pw = Ptr(Box::new(Wrapper(5))) as Ptr>; + assert_eq!(pw.ptr_wrapper(), 5); + + let wp = Wrapper(Ptr(Box::new(6))) as Wrapper>; + assert_eq!(wp.wrapper_ptr(), 6); + + let wpw = Wrapper(Ptr(Box::new(Wrapper(7)))) as Wrapper>>; + assert_eq!(wpw.wrapper_ptr_wrapper(), 7); +} 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 48918b996ef59..4dc481174a45d 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) -> usize; + fn foo(self: &Rc) -> usize; } trait Bar { - fn foo(self: Rc) -> usize where Self: Sized; - fn bar(self: Box) -> usize; + fn foo(self: &Rc) -> usize where Self: Sized; + fn bar(self: Rc) -> usize; } impl Foo for usize { - fn foo(self: Rc) -> usize { - *self + fn foo(self: &Rc) -> usize { + **self } } impl Bar for usize { - fn foo(self: Rc) -> usize { - *self + fn foo(self: &Rc) -> usize { + **self } - fn bar(self: Box) -> usize { + fn bar(self: Rc) -> usize { *self } } fn make_foo() { - let x = Box::new(5usize) as Box; + let x = Rc::new(5usize) as Rc; //~^ ERROR E0038 //~| ERROR E0038 } fn make_bar() { - let x = Box::new(5usize) as Box; + let x = Rc::new(5usize) as Rc; 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 ec9e65fc4c62d..715fc86517bee 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; - | ^^^^^^^^ the trait `Foo` cannot be made into an object +LL | let x = Rc::new(5usize) as Rc; + | ^^^^^^^ the trait `Foo` cannot be made into an object | - = note: method `foo` has a non-standard `self` type + = note: method `foo` has an uncoercible receiver type 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; - | ^^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object +LL | let x = Rc::new(5usize) as Rc; + | ^^^^^^^^^^^^^^^ 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>` for `std::boxed::Box` + = note: method `foo` has an uncoercible receiver type + = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::rc::Rc` error: aborting due to 2 previous errors diff --git a/src/test/ui/traits/trait-item-privacy.rs b/src/test/ui/traits/trait-item-privacy.rs index f8e4f0d596e20..1db5ec097376c 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 a3747bcee5d5c..1b0e7713ff3b6 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,7 +111,7 @@ 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 | ^^^^ ambiguous associated type @@ -143,7 +119,7 @@ LL | let _: S::A; //~ ERROR ambiguous associated type = note: specify the type using the syntax `::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 | ^^^^ ambiguous associated type @@ -151,7 +127,7 @@ LL | let _: S::B; //~ ERROR ambiguous associated type = note: specify the type using the syntax `::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 | ^^^^ ambiguous associated type @@ -159,18 +135,18 @@ LL | let _: S::C; //~ ERROR ambiguous associated type = note: specify the type using the syntax `::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 dac76fb57fd7c..01d7e89847a89 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).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 1e1fcbe340e58..db0cd38cb6a68 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::(); //~ 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).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).dup(); = note: method `blah` has generic type parameters = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` 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`.