From 0f0b7cbc4643d82a3ab2ddb3212d1d4c890419e4 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Mon, 2 Jul 2018 18:30:59 -0400 Subject: [PATCH 01/32] Make all object-safety methods require a global TyCtxt --- src/librustc/traits/error_reporting.rs | 4 ++-- src/librustc/traits/object_safety.rs | 2 +- src/librustc_typeck/astconv.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index b34378151ccb3..2a812d5231690 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -708,7 +708,7 @@ 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 +835,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..97a3c47459b2b 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -89,7 +89,7 @@ pub enum MethodViolationCode { NonStandardSelfType, } -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 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) From 6e05b92419fc6a0adc9af77b9c22048599a4e7c6 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Tue, 3 Jul 2018 00:48:52 -0400 Subject: [PATCH 02/32] Try to do the CoerceUnsized check for object safety - replaced NonStandardSelfType error with UncoercibleReceiver - add a method to global TyCtxt which does the CoerceUnsized check. This currently results in circular dependencies when compiling libcore ``` --- src/librustc/traits/object_safety.rs | 108 +++++++++++++++++++++++---- 1 file changed, 92 insertions(+), 16 deletions(-) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 97a3c47459b2b..bd677820fa44c 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -21,11 +21,13 @@ use super::elaborate_predicates; use hir::def_id::DefId; use lint; -use traits; -use ty::{self, Ty, TyCtxt, TypeFoldable}; +use traits::{self, Obligation, ObligationCause}; +use ty::{self, Ty, TyCtxt, TypeFoldable, Predicate, ToPredicate}; +use ty::subst::{Subst, Substs}; use ty::util::ExplicitSelf; 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,8 +87,8 @@ 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, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { @@ -277,23 +279,20 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, '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); + let receiver_ty = sig.skip_binder().inputs()[0]; + + if !self.receiver_is_coercible(method, receiver_ty) { + return Some(MethodViolationCode::UncoercibleReceiver); } - // 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); @@ -323,6 +322,83 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { None } + // checks the type of the self argument, and makes sure it implements + // the CoerceUnsized requirement: + // forall (U) { + // if (Self: Unsize) { + // Receiver: CoerceUnsized> + // } + // } + #[allow(dead_code)] + fn receiver_is_coercible( + self, + method: &ty::AssociatedItem, + receiver_ty: Ty<'tcx> + ) -> bool + { + let traits = (self.lang_items().unsize_trait(), + self.lang_items().coerce_unsized_trait()); + let (unsize_did, coerce_unsized_did) = if let (Some(u), Some(cu)) = traits { + (u, cu) + } else { + debug!("receiver_is_coercible: Missing Unsize or CoerceUnsized traits"); + return false; + }; + + // use a bogus type parameter to mimick a forall(U) query + // using u32::MAX for now. This is BAD and will probably break when + // this method is called recursively, or at least if someone does a hacky thing + // like this elsewhere in the compiler + let target_self_ty: Ty<'tcx> = self.mk_ty_param( + ::std::u32::MAX, + Name::intern("mikeyhewROCKS").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 + }; + + // the type `Receiver` in the query + let target_receiver_ty = receiver_ty.subst( + self, + self.mk_substs_trait(target_self_ty, &[]), + ); + + // Receiver: CoerceUnsized> + let obligation = { + let predicate = ty::TraitRef { + def_id: coerce_unsized_did, + substs: self.mk_substs_trait(self.mk_self_type(), &[target_receiver_ty.into()]), + }.to_predicate(); + + Obligation::new( + ObligationCause::dummy(), + param_env, + predicate, + ) + }; + + // return whether `Receiver: CoerceUnsized>` holds + self.infer_ctxt().enter(|ref infcx| { + infcx.predicate_must_hold(&obligation) + }) + } + fn contains_illegal_self_type_reference(self, trait_def_id: DefId, ty: Ty<'tcx>) From d3af46687d56e0011b4715db3fe2206a46f408f8 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Thu, 12 Jul 2018 21:57:26 -0400 Subject: [PATCH 03/32] reduce line length to please tidy --- src/librustc/traits/error_reporting.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 2a812d5231690..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.global_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) From 09202f3fe431c79958d07cafb2ede142a0880d0e Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Thu, 12 Jul 2018 22:01:36 -0400 Subject: [PATCH 04/32] do the coerce_unsized check last MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit it’s probably the most expensive checks, so this way we avoid doing it if another check fails first --- src/librustc/traits/object_safety.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index bd677820fa44c..6f6842dbe7c3d 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -286,13 +286,6 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { let sig = self.fn_sig(method.def_id); - let receiver_ty = sig.skip_binder().inputs()[0]; - - if !self.receiver_is_coercible(method, receiver_ty) { - return Some(MethodViolationCode::UncoercibleReceiver); - } - - 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); @@ -319,6 +312,12 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { return Some(MethodViolationCode::WhereClauseReferencesSelf(span)); } + let receiver_ty = sig.skip_binder().inputs()[0]; + + if !self.receiver_is_coercible(method, receiver_ty) { + return Some(MethodViolationCode::UncoercibleReceiver); + } + None } From 0f76082c0c09bf4dff446f49ff890cf407f4f3bb Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Thu, 12 Jul 2018 22:04:16 -0400 Subject: [PATCH 05/32] only check for object-safety if we have an inference variable This should hopefully avoid the issue of query cycles when checking object-safety. Maybe. Seems hacky --- src/librustc/traits/select.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) 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; From 76d3e73fb0426a2e625e5581934c5faef5b18386 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Fri, 13 Jul 2018 11:59:59 -0400 Subject: [PATCH 06/32] remove some `use` declarations that got added in during rebase --- src/librustc/traits/object_safety.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 6f6842dbe7c3d..159f192b0616d 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -23,8 +23,7 @@ use hir::def_id::DefId; use lint; use traits::{self, Obligation, ObligationCause}; use ty::{self, Ty, TyCtxt, TypeFoldable, Predicate, ToPredicate}; -use ty::subst::{Subst, Substs}; -use ty::util::ExplicitSelf; +use ty::subst::{Subst}; use std::borrow::Cow; use std::iter::{self}; use syntax::ast::{self, Name}; From ebe119991bb9845f9b04469715078f164071ab31 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Fri, 13 Jul 2018 15:58:35 -0400 Subject: [PATCH 07/32] Add some log messages to aid in debugging --- src/librustc/traits/object_safety.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 159f192b0616d..7ddddcd81d17d 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -114,6 +114,8 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, '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() @@ -334,6 +336,8 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { 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_unsized_trait()); let (unsize_did, coerce_unsized_did) = if let (Some(u), Some(cu)) = traits { From 04cbc1de35eaaa00e1ee4833618f4664f28595d1 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Fri, 13 Jul 2018 16:00:24 -0400 Subject: [PATCH 08/32] re-bind receiver_ty to avoid escaping regions errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Probably the better way to do this would be to use bound_map everywhere, instead of calling skip_binder in the first place. Oh well, let’s do this for now --- src/librustc/traits/object_safety.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 7ddddcd81d17d..483b354c49661 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -22,7 +22,7 @@ use super::elaborate_predicates; use hir::def_id::DefId; use lint; use traits::{self, Obligation, ObligationCause}; -use ty::{self, Ty, TyCtxt, TypeFoldable, Predicate, ToPredicate}; +use ty::{self, Ty, TyCtxt, Binder, TypeFoldable, Predicate, ToPredicate}; use ty::subst::{Subst}; use std::borrow::Cow; use std::iter::{self}; @@ -361,10 +361,10 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { let param_env = { let mut param_env = self.param_env(method.def_id); - let predicate = ty::TraitRef { + let predicate = Binder::bind(ty::TraitRef { def_id: unsize_did, substs: self.mk_substs_trait(self.mk_self_type(), &[target_self_ty.into()]), - }.to_predicate(); + }).to_predicate(); let caller_bounds: Vec> = param_env.caller_bounds.iter().cloned() .chain(iter::once(predicate)) @@ -383,10 +383,10 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { // Receiver: CoerceUnsized> let obligation = { - let predicate = ty::TraitRef { + let predicate = Binder::bind(ty::TraitRef { def_id: coerce_unsized_did, substs: self.mk_substs_trait(self.mk_self_type(), &[target_receiver_ty.into()]), - }.to_predicate(); + }).to_predicate(); Obligation::new( ObligationCause::dummy(), From 831e821938de60d159b07b1165dd5fc46114011f Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Fri, 13 Jul 2018 17:45:58 -0400 Subject: [PATCH 09/32] It's the receiver type we're checking, not Self fixes a bug that made everything non-object-safe --- src/librustc/traits/object_safety.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 483b354c49661..6c54324e35ad5 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -385,7 +385,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { let obligation = { let predicate = Binder::bind(ty::TraitRef { def_id: coerce_unsized_did, - substs: self.mk_substs_trait(self.mk_self_type(), &[target_receiver_ty.into()]), + substs: self.mk_substs_trait(receiver_ty, &[target_receiver_ty.into()]), }).to_predicate(); Obligation::new( From e5ca14c33c8d65e4d375c5800228c80696e11e3b Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Sun, 15 Jul 2018 11:18:36 -0400 Subject: [PATCH 10/32] allow `self: Self` as a special case for backward-compat --- src/librustc/traits/object_safety.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 6c54324e35ad5..f6f8664ebfd8e 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -315,8 +315,14 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { let receiver_ty = sig.skip_binder().inputs()[0]; - if !self.receiver_is_coercible(method, receiver_ty) { - return Some(MethodViolationCode::UncoercibleReceiver); + // 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 From 15092754bdc9851e84dd0ddbc4c38d326c01f390 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Sun, 15 Jul 2018 14:15:41 -0400 Subject: [PATCH 11/32] keep receiver_ty behind a Binder always Use `Binder::map_bound` to keep `receiver_ty`, `target_receiver_ty` and predicates bound by the method signature --- src/librustc/traits/object_safety.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index f6f8664ebfd8e..65cd86b46547b 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -313,13 +313,13 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { return Some(MethodViolationCode::WhereClauseReferencesSelf(span)); } - let receiver_ty = sig.skip_binder().inputs()[0]; + let receiver_ty = 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 *receiver_ty.skip_binder() != self.mk_self_type() { if !self.receiver_is_coercible(method, receiver_ty) { return Some(MethodViolationCode::UncoercibleReceiver); } @@ -339,7 +339,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { fn receiver_is_coercible( self, method: &ty::AssociatedItem, - receiver_ty: Ty<'tcx> + receiver_ty: Binder>, ) -> bool { debug!("receiver_is_coercible: method = {:?}, receiver_ty = {:?}", method, receiver_ty); @@ -367,10 +367,10 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { let param_env = { let mut param_env = self.param_env(method.def_id); - let predicate = Binder::bind(ty::TraitRef { + let predicate = ty::TraitRef { def_id: unsize_did, substs: self.mk_substs_trait(self.mk_self_type(), &[target_self_ty.into()]), - }).to_predicate(); + }.to_predicate(); let caller_bounds: Vec> = param_env.caller_bounds.iter().cloned() .chain(iter::once(predicate)) @@ -389,9 +389,11 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { // Receiver: CoerceUnsized> let obligation = { - let predicate = Binder::bind(ty::TraitRef { - def_id: coerce_unsized_did, - substs: self.mk_substs_trait(receiver_ty, &[target_receiver_ty.into()]), + let predicate = receiver_ty.fuse(target_receiver_ty, |receiver_ty, target_receiver_ty| { + ty::TraitRef { + def_id: coerce_unsized_did, + substs: self.mk_substs_trait(receiver_ty, &[target_receiver_ty.into()]), + } }).to_predicate(); Obligation::new( From 9cbce685ae56fc9b72c74f0466fb6ce11681f187 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Tue, 17 Jul 2018 12:00:54 -0400 Subject: [PATCH 12/32] call liberate_late_bound_regions on receiver_ty MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hopefully this will still work, and it might be a bit simpler than keeping the binder around. The point of this was to fix the ICE in substs.rs, but it looks like it’s caused by something else --- src/librustc/traits/object_safety.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 65cd86b46547b..841a5eac858aa 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -22,8 +22,7 @@ use super::elaborate_predicates; use hir::def_id::DefId; use lint; use traits::{self, Obligation, ObligationCause}; -use ty::{self, Ty, TyCtxt, Binder, TypeFoldable, Predicate, ToPredicate}; -use ty::subst::{Subst}; +use ty::{self, Ty, TyCtxt, TypeFoldable, Predicate, ToPredicate}; use std::borrow::Cow; use std::iter::{self}; use syntax::ast::{self, Name}; @@ -313,14 +312,17 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { return Some(MethodViolationCode::WhereClauseReferencesSelf(span)); } - let receiver_ty = sig.map_bound(|sig| sig.inputs()[0]); + 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.skip_binder() != self.mk_self_type() { - if !self.receiver_is_coercible(method, receiver_ty) { + if receiver_ty != self.mk_self_type() { + if !self.receiver_is_coercible(trait_def_id, method, receiver_ty) { return Some(MethodViolationCode::UncoercibleReceiver); } } @@ -339,7 +341,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { fn receiver_is_coercible( self, method: &ty::AssociatedItem, - receiver_ty: Binder>, + receiver_ty: Ty<'tcx>, ) -> bool { debug!("receiver_is_coercible: method = {:?}, receiver_ty = {:?}", method, receiver_ty); @@ -389,12 +391,10 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { // Receiver: CoerceUnsized> let obligation = { - let predicate = receiver_ty.fuse(target_receiver_ty, |receiver_ty, target_receiver_ty| { - ty::TraitRef { - def_id: coerce_unsized_did, - substs: self.mk_substs_trait(receiver_ty, &[target_receiver_ty.into()]), - } - }).to_predicate(); + let predicate = ty::TraitRef { + def_id: coerce_unsized_did, + substs: self.mk_substs_trait(receiver_ty, &[target_receiver_ty.into()]), + }.to_predicate(); Obligation::new( ObligationCause::dummy(), From e3b3167ab11ca9298982ce30cc039e9fb11d4e8d Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Tue, 17 Jul 2018 14:36:22 -0400 Subject: [PATCH 13/32] fix bug when trait arguments appear in `receiver_ty` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `ty::Substs` needs to have all type parameters present, even if they aren’t being substituted. This caused an ICE during substitution if one of the trait’s non-Self parameters (e.g. a lifetime) appeared in the receiver type --- src/librustc/traits/object_safety.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 841a5eac858aa..c3629b10fd346 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -23,6 +23,7 @@ use hir::def_id::DefId; use lint; use traits::{self, Obligation, ObligationCause}; use ty::{self, Ty, TyCtxt, TypeFoldable, Predicate, ToPredicate}; +use ty::subst::{Subst, Substs}; use std::borrow::Cow; use std::iter::{self}; use syntax::ast::{self, Name}; @@ -340,6 +341,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { #[allow(dead_code)] fn receiver_is_coercible( self, + trait_def_id: DefId, method: &ty::AssociatedItem, receiver_ty: Ty<'tcx>, ) -> bool @@ -383,11 +385,16 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { param_env }; + let receiver_substs = Substs::for_item(self, trait_def_id, |param, _| { + if param.index == 0 { + target_self_ty.into() + } else { + self.mk_param_from_def(param) + } + }); + // the type `Receiver` in the query - let target_receiver_ty = receiver_ty.subst( - self, - self.mk_substs_trait(target_self_ty, &[]), - ); + let target_receiver_ty = receiver_ty.subst(self, receiver_substs); // Receiver: CoerceUnsized> let obligation = { From 478763b5c81cc9739f197e115a506a9ecd1bae43 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Tue, 17 Jul 2018 14:39:16 -0400 Subject: [PATCH 14/32] update object-safety ui test for new object-safety rules --- .../arbitrary-self-types-not-object-safe.rs | 20 +++++++++---------- ...rbitrary-self-types-not-object-safe.stderr | 16 +++++++-------- 2 files changed, 18 insertions(+), 18 deletions(-) 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 From b31b0f9186a7ff0781e5c429a90dd984b64f8171 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Tue, 17 Jul 2018 18:46:49 -0400 Subject: [PATCH 15/32] create receiver_substs using the method's DefId MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit instead of the trait’s DefId. Apparently, when there are where clauses, the method has Substs that the trait doesn’t have. --- src/librustc/traits/object_safety.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index c3629b10fd346..0ad43f664d0f8 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -323,7 +323,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { // 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(trait_def_id, method, receiver_ty) { + if !self.receiver_is_coercible(method, receiver_ty) { return Some(MethodViolationCode::UncoercibleReceiver); } } @@ -341,7 +341,6 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { #[allow(dead_code)] fn receiver_is_coercible( self, - trait_def_id: DefId, method: &ty::AssociatedItem, receiver_ty: Ty<'tcx>, ) -> bool @@ -385,7 +384,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { param_env }; - let receiver_substs = Substs::for_item(self, trait_def_id, |param, _| { + let receiver_substs = Substs::for_item(self, method.def_id, |param, _| { if param.index == 0 { target_self_ty.into() } else { From 3e8c5bce7825a004e428bef3117142e40a123fa9 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Tue, 17 Jul 2018 18:52:50 -0400 Subject: [PATCH 16/32] update some compile-fail tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some errors, about trait objects not implementing their own trait when they aren’t object-safe, aren’t being reported. Here is the error missing from compile-fail/trait-test-2.rs: ``` error[E0277]: the trait bound `dyn bar: bar` is not satisfied --> src/test/compile-fail/trait-test-2.rs:20:26 | 20 | (box 10 as Box).dup(); | ^^^ the trait `bar` is not implemented for `dyn bar` ``` My best guess is it has to do with how object-safety checks now include trait-solving. It doesn’t look like a very useful error, so I’m not too worried. --- src/test/ui/traits/trait-item-privacy.rs | 2 -- src/test/ui/traits/trait-test-2.rs | 1 - 2 files changed, 3 deletions(-) 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-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 } From a63a201ba5f543ddd858bb65881d7e696fde6707 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Mon, 27 Aug 2018 17:07:26 -0400 Subject: [PATCH 17/32] Add the CoerceSized trait - add the CoerceSized trait and set it up as a lang item Object safety still uses CoerceUnsized for now --- src/liballoc/boxed.rs | 5 ++++- src/liballoc/lib.rs | 1 + src/liballoc/pin.rs | 7 ++++++- src/liballoc/rc.rs | 8 +++++++- src/liballoc/sync.rs | 7 ++++++- src/libcompiler_builtins | 2 +- src/libcore/marker.rs | 29 +++++++++++++++++++++++++++++ src/libcore/ops/unsize.rs | 2 +- src/libcore/pin.rs | 5 ++++- src/librustc/middle/lang_items.rs | 1 + src/llvm | 2 +- src/tools/clippy | 2 +- 12 files changed, 62 insertions(+), 9 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index c25f3eb8f1750..2cfabc094f256 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -63,7 +63,7 @@ use core::fmt; use core::future::{Future, FutureObj, LocalFutureObj, UnsafeFutureObj}; use core::hash::{Hash, Hasher}; use core::iter::FusedIterator; -use core::marker::{Unpin, Unsize}; +use core::marker::{Unpin, Unsize, CoerceSized}; use core::mem; use core::pin::PinMut; use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState}; @@ -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..0a405131c0598 100644 --- a/src/liballoc/pin.rs +++ b/src/liballoc/pin.rs @@ -91,7 +91,7 @@ pub use core::marker::Unpin; use core::convert::From; use core::fmt; use core::future::{Future, FutureObj, LocalFutureObj, UnsafeFutureObj}; -use core::marker::Unsize; +use core::marker::{Unsize, CoerceSized}; use core::ops::{CoerceUnsized, Deref, DerefMut}; use core::task::{Context, Poll}; @@ -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..d3103f81419e7 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -252,7 +252,7 @@ use core::fmt; use core::hash::{Hash, Hasher}; use core::intrinsics::abort; use core::marker; -use core::marker::{Unsize, PhantomData}; +use core::marker::{Unsize, CoerceSized, PhantomData}; use core::mem::{self, align_of_val, forget, size_of_val}; use core::ops::Deref; use core::ops::CoerceUnsized; @@ -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..474d45ba134ec 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -27,7 +27,7 @@ use core::mem::{self, align_of_val, size_of_val}; use core::ops::Deref; use core::ops::CoerceUnsized; use core::ptr::{self, NonNull}; -use core::marker::{Unsize, PhantomData}; +use core::marker::{Unsize, CoerceSized, PhantomData}; use core::hash::{Hash, Hasher}; use core::{isize, usize}; use core::convert::From; @@ -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/libcompiler_builtins b/src/libcompiler_builtins index f3a13eb2384c7..d549d85b1735d 160000 --- a/src/libcompiler_builtins +++ b/src/libcompiler_builtins @@ -1 +1 @@ -Subproject commit f3a13eb2384c7cbb91b6db5b008377e9710d434c +Subproject commit d549d85b1735dc5066b2973f8549557a813bb9c8 diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index dd57d2dd00910..b081d703a9ee6 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -20,6 +20,7 @@ use cell::UnsafeCell; use cmp; use hash::Hash; use hash::Hasher; +use ops::CoerceUnsized; /// Types that can be transferred across thread boundaries. /// @@ -135,6 +136,34 @@ pub trait Unsize { // Empty. } +/// 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 is dyn Trait to the version where Self is the erased sized type T that implements Trait. +/// +/// 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 {} + + /// Types whose values can be duplicated simply by copying bits. /// /// By default, variable bindings have 'move semantics.' In other diff --git a/src/libcore/ops/unsize.rs b/src/libcore/ops/unsize.rs index da72f3748425d..285895412b9cc 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. } diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index e9001f86b3526..cd553d3cf29c1 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -8,7 +8,7 @@ use fmt; use future::{Future, UnsafeFutureObj}; -use marker::{Sized, Unpin, Unsize}; +use marker::{Sized, Unpin, Unsize, CoerceSized}; use task::{Context, Poll}; use ops::{Deref, DerefMut, CoerceUnsized}; @@ -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/llvm b/src/llvm index 2a1cdeadd3ea8..e19f07f5a6e55 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 2a1cdeadd3ea8e1eba9cc681037b83f07332763b +Subproject commit e19f07f5a6e5546ab4f6ea951e3c6b8627edeaa7 diff --git a/src/tools/clippy b/src/tools/clippy index 131c8f86b2b71..628934424e9c1 160000 --- a/src/tools/clippy +++ b/src/tools/clippy @@ -1 +1 @@ -Subproject commit 131c8f86b2b712d4d9b00f486b6c67f97782228a +Subproject commit 628934424e9c181a4162b3a5d01e4211ee98b7b7 From 2598c1f9bab8900fbcdad84aad71e7aa84101044 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Tue, 28 Aug 2018 00:37:26 -0400 Subject: [PATCH 18/32] switch from using CoerceUnsized to CoerceSized for the object-safety check --- src/librustc/traits/object_safety.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 0ad43f664d0f8..1fa40e209eb04 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -348,8 +348,8 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { debug!("receiver_is_coercible: method = {:?}, receiver_ty = {:?}", method, receiver_ty); let traits = (self.lang_items().unsize_trait(), - self.lang_items().coerce_unsized_trait()); - let (unsize_did, coerce_unsized_did) = if let (Some(u), Some(cu)) = traits { + 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 CoerceUnsized traits"); @@ -398,7 +398,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { // Receiver: CoerceUnsized> let obligation = { let predicate = ty::TraitRef { - def_id: coerce_unsized_did, + def_id: coerce_sized_did, substs: self.mk_substs_trait(receiver_ty, &[target_receiver_ty.into()]), }.to_predicate(); From c236af36349d0fe8b2c538bef0817101dc5e30a0 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Thu, 30 Aug 2018 02:46:00 -0400 Subject: [PATCH 19/32] update comments and fix bug in object_safety.rs - replaced comment with doc comment on receiver_is_coercible, and rewrote it to explain more clearly what a receiver is, and gave examples of coercible and incoercible receivers. - replaced `mikeyhewROCKS` with `RustaceansAreAwesome`, to better appeal to the broader audience of rustaceans. - updated comments to reflect the fact that CoerceSized is used instead of CoerceUnsized - change the predicate from `Receiver: CoerceSized U]>`, which is a bug, to `Receiver[Self -> U]>: CoerceSized` --- src/librustc/traits/object_safety.rs | 58 ++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 1fa40e209eb04..0aec16787ab65 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -331,13 +331,40 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { None } - // checks the type of the self argument, and makes sure it implements - // the CoerceUnsized requirement: - // forall (U) { - // if (Self: Unsize) { - // Receiver: CoerceUnsized> - // } - // } + /// 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 value. + /// 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` => `dyn Trait: CoerceSized` + /// - `&'a mut self` => `&'a mut dyn Trait: CoerceSized<&'a mut T>` + /// - `self: Rc` => `Rc: CoerceSized>` + /// + /// examples where this does *not* hold, and the receiver is not object safe: + /// - `self: &&Self`. There is no way to turn an `&&dyn Trait` into an `&&T`. To do so, you + /// would need to change the inner `&` from a fat pointer to a thin pointer... TODO + /// + /// 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, @@ -357,12 +384,11 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { }; // use a bogus type parameter to mimick a forall(U) query - // using u32::MAX for now. This is BAD and will probably break when - // this method is called recursively, or at least if someone does a hacky thing - // like this elsewhere in the compiler + // 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("mikeyhewROCKS").as_interned_str(), + Name::intern("RustaceansAreAwesome").as_interned_str(), ); // create a modified param env, with @@ -391,15 +417,14 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { self.mk_param_from_def(param) } }); + // the type `Receiver[Self -> U]` in the query + let unsized_receiver_ty = receiver_ty.subst(self, receiver_substs); - // the type `Receiver` in the query - let target_receiver_ty = receiver_ty.subst(self, receiver_substs); - - // Receiver: CoerceUnsized> + // Receiver[Self -> U]: CoerceSized let obligation = { let predicate = ty::TraitRef { def_id: coerce_sized_did, - substs: self.mk_substs_trait(receiver_ty, &[target_receiver_ty.into()]), + substs: self.mk_substs_trait(unsized_receiver_ty, &[receiver_ty.into()]), }.to_predicate(); Obligation::new( @@ -409,7 +434,6 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { ) }; - // return whether `Receiver: CoerceUnsized>` holds self.infer_ctxt().enter(|ref infcx| { infcx.predicate_must_hold(&obligation) }) From ffcadd406312189d9b2db83b70d47ca8b11821c1 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Sun, 2 Sep 2018 00:30:55 -0400 Subject: [PATCH 20/32] update code comments in object-safety.rs --- src/librustc/traits/object_safety.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 0aec16787ab65..083ed783022b1 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -379,7 +379,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { let (unsize_did, coerce_sized_did) = if let (Some(u), Some(cu)) = traits { (u, cu) } else { - debug!("receiver_is_coercible: Missing Unsize or CoerceUnsized traits"); + debug!("receiver_is_coercible: Missing Unsize or CoerceSized traits"); return false; }; @@ -435,6 +435,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { }; self.infer_ctxt().enter(|ref infcx| { + // the receiver is coercible iff the obligation holds infcx.predicate_must_hold(&obligation) }) } From f85e838c5abacf5b798f94b6f39d43ab26313f94 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Sun, 2 Sep 2018 00:47:19 -0400 Subject: [PATCH 21/32] update doc comments and fix tidy lints --- src/libcore/marker.rs | 4 +++- src/librustc/traits/object_safety.rs | 16 +++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index b081d703a9ee6..cd98692449c9a 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -138,7 +138,9 @@ pub trait Unsize { /// 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 is dyn Trait to the version where Self is the erased sized type T that implements Trait. +/// 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 diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 083ed783022b1..08c037f9a9cb3 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -333,7 +333,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { /// 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 value. + /// 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: @@ -344,13 +344,15 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { /// (substitution notation). /// /// some examples of receiver types and their required obligation - /// - `self` => `dyn Trait: CoerceSized` - /// - `&'a mut self` => `&'a mut dyn Trait: CoerceSized<&'a mut T>` - /// - `self: Rc` => `Rc: CoerceSized>` + /// - `self` requires `dyn Trait: CoerceSized` + /// - `&'a mut self` requires `&'a mut dyn Trait: CoerceSized<&'a mut T>` + /// - `self: Rc` requires `Rc: CoerceSized>` /// - /// examples where this does *not* hold, and the receiver is not object safe: - /// - `self: &&Self`. There is no way to turn an `&&dyn Trait` into an `&&T`. To do so, you - /// would need to change the inner `&` from a fat pointer to a thin pointer... TODO + /// 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 From 85b25a67e4e4ec398126bd4321ded88712d8e18c Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Sun, 2 Sep 2018 01:31:32 -0400 Subject: [PATCH 22/32] update object_safety module-level documentation --- src/librustc/traits/object_safety.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 08c037f9a9cb3..1a579441a90a8 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 From 39e13aefb9cac1a2a956278e16f37a54988a48b3 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Sun, 2 Sep 2018 01:32:01 -0400 Subject: [PATCH 23/32] use [X => Y] instead of [X -> Y] for substitution notation --- src/librustc/traits/object_safety.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 1a579441a90a8..8937bc3be10a9 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -339,9 +339,9 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { /// - let `Receiver` be the type of the `self` argument, i.e `Self`, `&Self`, `Rc` /// - require the following bound: /// forall(T: Trait) { - /// Receiver[Self -> dyn Trait]: CoerceSized T]> + /// Receiver[Self => dyn Trait]: CoerceSized T]> /// } - /// 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). /// /// some examples of receiver types and their required obligation @@ -361,7 +361,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { /// the implementation, we use the following, more general bound: /// forall (U: ?Sized) { /// if (Self: Unsize) { - /// Receiver[Self -> U]: CoerceSized + /// Receiver[Self => U]: CoerceSized /// } /// } /// @@ -420,10 +420,10 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { self.mk_param_from_def(param) } }); - // 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); - // Receiver[Self -> U]: CoerceSized + // Receiver[Self => U]: CoerceSized let obligation = { let predicate = ty::TraitRef { def_id: coerce_sized_did, From 9bfb39d715223eade059240a4201849c610b1886 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Sun, 2 Sep 2018 01:51:34 -0400 Subject: [PATCH 24/32] address nit about `{` being on the wrong line --- src/librustc/traits/object_safety.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 8937bc3be10a9..f6e37fae69d5f 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -373,8 +373,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { self, method: &ty::AssociatedItem, receiver_ty: Ty<'tcx>, - ) -> bool - { + ) -> bool { debug!("receiver_is_coercible: method = {:?}, receiver_ty = {:?}", method, receiver_ty); let traits = (self.lang_items().unsize_trait(), From 6b14a12bb1dc318f2e30ae8a6e470d7d3f4905b8 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Mon, 3 Sep 2018 19:37:49 -0400 Subject: [PATCH 25/32] add ICE message explaining that custom receivers dynamic dispatch is not implemented yet --- src/librustc_codegen_llvm/abi.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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); From 2739801f67d55ebabe7fc9684b672b2b33cbbe9d Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Mon, 3 Sep 2018 22:38:24 -0400 Subject: [PATCH 26/32] Finish updating ui tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It looks like I forgot to finish updating these ui tests — I updated the source files already, but forgot to change the .stderr files --- src/test/ui/traits/trait-item-privacy.stderr | 38 ++++---------------- src/test/ui/traits/trait-test-2.stderr | 10 ++---- 2 files changed, 9 insertions(+), 39 deletions(-) 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.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`. From e972b2b51b8b0ceba6aa3ae24f4f09a9366dc868 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Mon, 3 Sep 2018 22:48:13 -0400 Subject: [PATCH 27/32] Move CoerceSized from marker to ops So it can be right beside CoerceUnsized --- src/liballoc/boxed.rs | 4 ++-- src/liballoc/pin.rs | 4 ++-- src/liballoc/rc.rs | 4 ++-- src/liballoc/sync.rs | 4 ++-- src/libcore/marker.rs | 30 ------------------------------ src/libcore/ops/mod.rs | 3 +++ src/libcore/ops/unsize.rs | 31 +++++++++++++++++++++++++++++++ src/libcore/pin.rs | 4 ++-- 8 files changed, 44 insertions(+), 40 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 2cfabc094f256..be70ed9191c41 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -63,10 +63,10 @@ use core::fmt; use core::future::{Future, FutureObj, LocalFutureObj, UnsafeFutureObj}; use core::hash::{Hash, Hasher}; use core::iter::FusedIterator; -use core::marker::{Unpin, Unsize, CoerceSized}; +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}; diff --git a/src/liballoc/pin.rs b/src/liballoc/pin.rs index 0a405131c0598..51b1111a67b39 100644 --- a/src/liballoc/pin.rs +++ b/src/liballoc/pin.rs @@ -91,8 +91,8 @@ pub use core::marker::Unpin; use core::convert::From; use core::fmt; use core::future::{Future, FutureObj, LocalFutureObj, UnsafeFutureObj}; -use core::marker::{Unsize, CoerceSized}; -use core::ops::{CoerceUnsized, Deref, DerefMut}; +use core::marker::Unsize; +use core::ops::{CoerceUnsized, CoerceSized, Deref, DerefMut}; use core::task::{Context, Poll}; use boxed::Box; diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index d3103f81419e7..4ab65fde9b79e 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -252,10 +252,10 @@ use core::fmt; use core::hash::{Hash, Hasher}; use core::intrinsics::abort; use core::marker; -use core::marker::{Unsize, CoerceSized, PhantomData}; +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; diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 474d45ba134ec..36a1db833cfc0 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -25,9 +25,9 @@ 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, CoerceSized, PhantomData}; +use core::marker::{Unsize, PhantomData}; use core::hash::{Hash, Hasher}; use core::{isize, usize}; use core::convert::From; diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index cd98692449c9a..fcc1e8c13fdb8 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -20,7 +20,6 @@ use cell::UnsafeCell; use cmp; use hash::Hash; use hash::Hasher; -use ops::CoerceUnsized; /// Types that can be transferred across thread boundaries. /// @@ -136,35 +135,6 @@ pub trait Unsize { // Empty. } -/// 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 {} - /// Types whose values can be duplicated simply by copying bits. /// diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs index ce4f45762de48..a5055a581a376 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 = "27732")] +pub use self::unsize::CoerceSized; diff --git a/src/libcore/ops/unsize.rs b/src/libcore/ops/unsize.rs index 285895412b9cc..4faace26b02f9 100644 --- a/src/libcore/ops/unsize.rs +++ b/src/libcore/ops/unsize.rs @@ -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 cd553d3cf29c1..f05bc59178284 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -8,9 +8,9 @@ use fmt; use future::{Future, UnsafeFutureObj}; -use marker::{Sized, Unpin, Unsize, CoerceSized}; +use marker::{Sized, Unpin, Unsize}; use task::{Context, Poll}; -use ops::{Deref, DerefMut, CoerceUnsized}; +use ops::{Deref, DerefMut, CoerceUnsized, CoerceSized}; /// A pinned reference. /// From 3c6fcdeb14eded28be051aeaabbcc3f2e49d9ae3 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Tue, 4 Sep 2018 10:19:04 -0400 Subject: [PATCH 28/32] Add a test with pointers and wrappers This will be converted to a run-pass test once dynamic dispatch is implemented --- ...itrary_self_types_pointers_and_wrappers.rs | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 src/test/compile-fail/arbitrary_self_types_pointers_and_wrappers.rs 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); +} From 01d0a2eac51ca41dc040de6dae4119f976e65ef0 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Tue, 4 Sep 2018 10:19:30 -0400 Subject: [PATCH 29/32] fix issue number for coerce_sized feature There is still no tracking issue, so just use 0 --- src/libcore/ops/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs index a5055a581a376..bf9775e2ae813 100644 --- a/src/libcore/ops/mod.rs +++ b/src/libcore/ops/mod.rs @@ -202,5 +202,5 @@ pub use self::generator::{Generator, GeneratorState}; #[unstable(feature = "coerce_unsized", issue = "27732")] pub use self::unsize::CoerceUnsized; -#[unstable(feature = "coerce_sized", issue = "27732")] +#[unstable(feature = "coerce_sized", issue = "0")] pub use self::unsize::CoerceSized; From ad8f4c086ab4e3695ffa3da925bba11545731860 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Tue, 4 Sep 2018 20:45:37 -0400 Subject: [PATCH 30/32] Add a positive test using stdlib pointers test includes `Rc`, `Arc,` `PinMut`, and `PinBox` as receiver types. To be converted to a run-pass test once dynamic dispatch is implemented. --- .../arbitrary-self-types-stdlib-pointers.rs | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/test/compile-fail/arbitrary-self-types-stdlib-pointers.rs 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()); +} From ac7677f4f93ef1b2ea7270124605555c4b16b724 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Wed, 5 Sep 2018 16:57:55 -0400 Subject: [PATCH 31/32] Undo submodule changes in a63a201ba5f543ddd858bb65881d7e696fde6707 --- src/libcompiler_builtins | 2 +- src/llvm | 2 +- src/tools/clippy | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcompiler_builtins b/src/libcompiler_builtins index d549d85b1735d..f3a13eb2384c7 160000 --- a/src/libcompiler_builtins +++ b/src/libcompiler_builtins @@ -1 +1 @@ -Subproject commit d549d85b1735dc5066b2973f8549557a813bb9c8 +Subproject commit f3a13eb2384c7cbb91b6db5b008377e9710d434c diff --git a/src/llvm b/src/llvm index e19f07f5a6e55..2a1cdeadd3ea8 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit e19f07f5a6e5546ab4f6ea951e3c6b8627edeaa7 +Subproject commit 2a1cdeadd3ea8e1eba9cc681037b83f07332763b diff --git a/src/tools/clippy b/src/tools/clippy index 628934424e9c1..131c8f86b2b71 160000 --- a/src/tools/clippy +++ b/src/tools/clippy @@ -1 +1 @@ -Subproject commit 628934424e9c181a4162b3a5d01e4211ee98b7b7 +Subproject commit 131c8f86b2b712d4d9b00f486b6c67f97782228a From c5a8553a7e2530aa002836d6dd392fdb5ffedb73 Mon Sep 17 00:00:00 2001 From: Michael Hewson Date: Thu, 6 Sep 2018 02:32:48 -0400 Subject: [PATCH 32/32] remove stray newline --- src/libcore/marker.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index fcc1e8c13fdb8..dd57d2dd00910 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -135,7 +135,6 @@ pub trait Unsize { // Empty. } - /// Types whose values can be duplicated simply by copying bits. /// /// By default, variable bindings have 'move semantics.' In other