diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 74354f605e537..a10ad6caaf4e5 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -77,7 +77,9 @@ use core::iter::FusedIterator; use core::marker::{Unpin, Unsize}; use core::mem; use core::pin::Pin; -use core::ops::{CoerceUnsized, DispatchFromDyn, Deref, DerefMut, Generator, GeneratorState}; +use core::ops::{ + CoerceUnsized, DispatchFromDyn, Deref, DerefMut, Receiver, Generator, GeneratorState +}; use core::ptr::{self, NonNull, Unique}; use core::task::{LocalWaker, Poll}; @@ -582,6 +584,9 @@ impl DerefMut for Box { } } +#[unstable(feature = "receiver_trait", issue = "0")] +impl Receiver for Box {} + #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for Box { type Item = I::Item; diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index ad6e594c884af..3d7b8c42c3d30 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -104,6 +104,7 @@ #![feature(ptr_internals)] #![feature(ptr_offset_from)] #![feature(rustc_attrs)] +#![feature(receiver_trait)] #![feature(specialization)] #![feature(split_ascii_whitespace)] #![feature(staged_api)] diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index be452ebb45a3c..5e0524363714f 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -254,7 +254,7 @@ use core::intrinsics::abort; use core::marker; use core::marker::{Unpin, Unsize, PhantomData}; use core::mem::{self, align_of_val, forget, size_of_val}; -use core::ops::Deref; +use core::ops::{Deref, Receiver}; use core::ops::{CoerceUnsized, DispatchFromDyn}; use core::pin::Pin; use core::ptr::{self, NonNull}; @@ -810,6 +810,9 @@ impl Deref for Rc { } } +#[unstable(feature = "receiver_trait", issue = "0")] +impl Receiver for Rc {} + #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc { /// Drops the `Rc`. diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index d388f76d8e84c..ff7426e99f7c6 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -24,7 +24,7 @@ use core::fmt; 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::{Deref, Receiver}; use core::ops::{CoerceUnsized, DispatchFromDyn}; use core::pin::Pin; use core::ptr::{self, NonNull}; @@ -764,6 +764,9 @@ impl Deref for Arc { } } +#[unstable(feature = "receiver_trait", issue = "0")] +impl Receiver for Arc {} + impl Arc { /// Makes a mutable reference into the given `Arc`. /// diff --git a/src/libcore/ops/deref.rs b/src/libcore/ops/deref.rs index 91a3d77e8b2ef..1b3bcdb0a8c21 100644 --- a/src/libcore/ops/deref.rs +++ b/src/libcore/ops/deref.rs @@ -177,3 +177,18 @@ pub trait DerefMut: Deref { impl DerefMut for &mut T { fn deref_mut(&mut self) -> &mut T { *self } } + +/// A subtrait of `Deref` that indicates that a struct can be used as a method receiver, without the +/// `arbitrary_self_types` feature. This is implemented by stdlib pointer types like `Box`, +/// `Rc`, `&T`, and `Pin

`. +#[cfg_attr(not(stage0), lang = "receiver")] +#[unstable(feature = "receiver_trait", issue = "0")] +pub trait Receiver: Deref { + // Empty. +} + +#[unstable(feature = "receiver_trait", issue = "0")] +impl Receiver for &T {} + +#[unstable(feature = "receiver_trait", issue = "0")] +impl Receiver for &mut T {} diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs index edfa6df11aceb..1a3b4666d2eae 100644 --- a/src/libcore/ops/mod.rs +++ b/src/libcore/ops/mod.rs @@ -178,6 +178,9 @@ pub use self::bit::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssig #[stable(feature = "rust1", since = "1.0.0")] pub use self::deref::{Deref, DerefMut}; +#[unstable(feature = "receiver_trait", issue = "0")] +pub use self::deref::Receiver; + #[stable(feature = "rust1", since = "1.0.0")] pub use self::drop::Drop; diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 68de82d294529..ea9152e753cc0 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -91,7 +91,7 @@ use fmt; use marker::Sized; -use ops::{Deref, DerefMut, CoerceUnsized, DispatchFromDyn}; +use ops::{Deref, DerefMut, Receiver, CoerceUnsized, DispatchFromDyn}; #[doc(inline)] pub use marker::Unpin; @@ -292,6 +292,9 @@ where } } +#[unstable(feature = "receiver_trait", issue = "0")] +impl Receiver for Pin

{} + #[unstable(feature = "pin", issue = "49150")] impl fmt::Debug for Pin

{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index cce8081daf28e..a5a519e83f7db 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -302,6 +302,7 @@ language_item_table! { DerefTraitLangItem, "deref", deref_trait, Target::Trait; DerefMutTraitLangItem, "deref_mut", deref_mut_trait, Target::Trait; + ReceiverTraitLangItem, "receiver", receiver_trait, Target::Trait; FnTraitLangItem, "fn", fn_trait, Target::Trait; FnMutTraitLangItem, "fn_mut", fn_mut_trait, Target::Trait; diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 73489309d0742..ca877346a9277 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -38,6 +38,7 @@ pub struct Autoderef<'a, 'gcx: 'tcx, 'tcx: 'a> { obligations: Vec>, at_start: bool, include_raw_pointers: bool, + require_receiver_trait: bool, span: Span, } @@ -136,12 +137,31 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { trait_ref, Ident::from_str("Target"), ), - cause, + cause.clone(), 0, &mut self.obligations); debug!("overloaded_deref_ty({:?}) = {:?}", ty, normalized_ty); + if self.require_receiver_trait { + // cur_ty: Receiver + let trait_ref = TraitRef { + def_id: tcx.lang_items().receiver_trait()?, + substs: tcx.mk_substs_trait(self.cur_ty, &[]), + }; + + let obligation = traits::Obligation::new( + cause.clone(), + self.fcx.param_env, + trait_ref.to_predicate() + ); + + if !self.fcx.predicate_may_hold(&obligation) { + debug!("overloaded_deref_ty: `Receiver` trait not implemented"); + return None; + } + } + Some(self.fcx.resolve_type_vars_if_possible(&normalized_ty)) } @@ -211,6 +231,14 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { self } + /// require the `Receiver` trait, a subtrait of `Deref` + /// this is used to make sure only stdlib receiver types like `&T` and `Rc` + /// are allowed without #![feature(arbitrary_self_types)] + pub fn require_receiver_trait(mut self) -> Self { + self.require_receiver_trait = true; + self + } + pub fn finalize(self) { let fcx = self.fcx; fcx.register_predicates(self.into_obligations()); @@ -230,6 +258,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { obligations: vec![], at_start: true, include_raw_pointers: false, + require_receiver_trait: false, span, } } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index ea84e874b1a5b..36a35faaf4ced 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -9,13 +9,13 @@ // except according to those terms. use check::{Inherited, FnCtxt}; +use check::autoderef::Autoderef; use constrained_type_params::{identify_constrained_type_params, Parameter}; use hir::def_id::DefId; use rustc::traits::{self, ObligationCauseCode}; use rustc::ty::{self, Lift, Ty, TyCtxt, TyKind, GenericParamDefKind, TypeFoldable}; use rustc::ty::subst::{Subst, Substs}; -use rustc::ty::util::ExplicitSelf; use rustc::util::nodemap::{FxHashSet, FxHashMap}; use rustc::middle::lang_items; use rustc::infer::opaque_types::may_define_existential_type; @@ -751,61 +751,91 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, &ty::Binder::bind(self_arg_ty) ); - let mut autoderef = fcx.autoderef(span, self_arg_ty).include_raw_pointers(); + if fcx.tcx.features().arbitrary_self_types { + let mut autoderef = fcx.autoderef(span, self_arg_ty) + .include_raw_pointers(); - loop { - if let Some((potential_self_ty, _)) = autoderef.next() { - debug!("check_method_receiver: potential self type `{:?}` to match `{:?}`", - potential_self_ty, self_ty); + if let Some(potential_self_ty) = receiver_derefs_to_self(fcx, &mut autoderef, self_ty) { + autoderef.finalize(); - if fcx.infcx.can_eq(fcx.param_env, self_ty, potential_self_ty).is_ok() { - autoderef.finalize(); - if let Some(mut err) = fcx.demand_eqtype_with_origin( - &cause, self_ty, potential_self_ty) { - err.emit(); - } - break + if let Some(mut err) = fcx.demand_eqtype_with_origin( + &cause, self_ty, potential_self_ty) { + err.emit(); } } else { + // report error, arbitrary_self_types was enabled fcx.tcx.sess.diagnostic().mut_span_err( - span, &format!("invalid `self` type: {:?}", self_arg_ty)) - .note(&format!("type must be `{:?}` or a type that dereferences to it", self_ty)) + span, &format!("invalid `self` type: {:?}", self_arg_ty) + ).note(&format!("type must be `{:?}` or a type that dereferences to it", self_ty)) .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box`") .code(DiagnosticId::Error("E0307".into())) .emit(); - return } - } - - let is_self_ty = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok(); - let self_kind = ExplicitSelf::determine(self_arg_ty, is_self_ty); + } else { + let mut autoderef = fcx.autoderef(span, self_arg_ty) + .require_receiver_trait(); + + if let Some(potential_self_ty) = receiver_derefs_to_self(fcx, &mut autoderef, self_ty) { + // receiver works fine + autoderef.finalize(); + if let Some(mut err) = fcx.demand_eqtype_with_origin( + &cause, self_ty, potential_self_ty) { + err.emit(); + } + } else { + // try again using `arbitrary_self_types` rules, to get a better error message + // don't require receiver trait, and allow raw pointer receivers - if !fcx.tcx.features().arbitrary_self_types { - match self_kind { - ExplicitSelf::ByValue | - ExplicitSelf::ByReference(_, _) | - ExplicitSelf::ByBox => (), + let mut autoderef = fcx.autoderef(span, self_arg_ty) + .include_raw_pointers(); - ExplicitSelf::ByRawPointer(_) => { + if let Some(_) = receiver_derefs_to_self(fcx, &mut autoderef, self_ty) { + // report error, would have worked with arbitrary_self_types feature_gate::feature_err( &fcx.tcx.sess.parse_sess, "arbitrary_self_types", span, GateIssue::Language, - "raw pointer `self` is unstable") + &format!( + "`{}` cannot be used as the type of `self` without \ + the `arbitrary_self_types` feature", + self_arg_ty, + ), + ).help("consider changing to `self`, `&self`, `&mut self`, or `self: Box`") + .emit(); + } else { + // report error, would not have worked with arbitrary_self_types + fcx.tcx.sess.diagnostic().mut_span_err( + span, &format!("invalid `self` type: {:?}", self_arg_ty) + ).note(&format!("type must be `{:?}` or a type that dereferences to it", self_ty)) .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box`") + .code(DiagnosticId::Error("E0307".into())) .emit(); } + } + } +} - ExplicitSelf::Other => { - feature_gate::feature_err( - &fcx.tcx.sess.parse_sess, - "arbitrary_self_types", - span, - GateIssue::Language,"arbitrary `self` types are unstable") - .help("consider changing to `self`, `&self`, `&mut self`, or `self: Box`") - .emit(); +/// Returns true if the Autoderef's final type can equal self_ty +fn receiver_derefs_to_self<'fcx, 'tcx, 'gcx>( + fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, + autoderef: &mut Autoderef<'fcx, 'gcx, 'tcx>, + self_ty: Ty<'tcx> +) -> Option> { + loop { + if let Some((potential_self_ty, _)) = autoderef.next() { + debug!("receiver_derefs_to_self: potential self type `{:?}` to match `{:?}`", + potential_self_ty, self_ty); + + let can_eq_self = fcx.infcx.can_eq( + fcx.param_env, self_ty, potential_self_ty + ).is_ok(); + + if can_eq_self { + return Some(potential_self_ty) } + } else { + return None } } } diff --git a/src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs b/src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs index 80a7ce9691126..c3ea0f1c73687 100644 --- a/src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs +++ b/src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(arbitrary_self_types)] #![feature(pin)] #![feature(rustc_attrs)] @@ -23,6 +22,7 @@ trait Trait { fn by_arc(self: Arc) -> i64; fn by_pin_mut(self: Pin<&mut Self>) -> i64; fn by_pin_box(self: Pin>) -> i64; + fn by_pin_pin_pin_ref(self: Pin>>) -> i64; } impl Trait for i64 { @@ -38,6 +38,17 @@ impl Trait for i64 { fn by_pin_box(self: Pin>) -> i64 { *self } + fn by_pin_pin_pin_ref(self: Pin>>) -> i64 { + *self + } +} + +struct Foo; + +impl Foo { + fn by_box_rc(self: Box>) -> i32 { + 11 + } } fn main() { @@ -53,4 +64,10 @@ fn main() { let pin_box = Into::>>::into(Box::new(4i64)) as Pin>; assert_eq!(4, pin_box.by_pin_box()); + + let value = 5i64; + let pin_pin_pin_ref = Pin::new(Pin::new(Pin::new(&value))) as Pin>>; + assert_eq!(5, pin_pin_pin_ref.by_pin_pin_pin_ref()); + + assert_eq!(11, Box::new(Rc::new(Foo)).by_box_rc()); } diff --git a/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.rs b/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.rs index ff0306f199310..84cd5c2bffa62 100644 --- a/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.rs +++ b/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.rs @@ -8,20 +8,32 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::rc::Rc; +use std::{ + ops::Deref, +}; + +struct Ptr(Box); + +impl Deref for Ptr { + type Target = T; + + fn deref(&self) -> &T { + &*self.0 + } +} trait Foo { - fn foo(self: Rc>); //~ ERROR arbitrary `self` types are unstable + fn foo(self: Ptr); //~ ERROR `Ptr` cannot be used as the type of `self` without } struct Bar; impl Foo for Bar { - fn foo(self: Rc>) {} //~ ERROR arbitrary `self` types are unstable + fn foo(self: Ptr) {} //~ ERROR `Ptr` cannot be used as the type of `self` without } impl Bar { - fn bar(self: Box>) {} //~ ERROR arbitrary `self` types are unstable + fn bar(self: Box>) {} //~ ERROR `std::boxed::Box>` cannot be used as the } fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr b/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr index ea259aa22adfb..c70774b3710de 100644 --- a/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr +++ b/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr @@ -1,26 +1,26 @@ -error[E0658]: arbitrary `self` types are unstable (see issue #44874) - --> $DIR/feature-gate-arbitrary-self-types.rs:14:18 +error[E0658]: `Ptr` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874) + --> $DIR/feature-gate-arbitrary-self-types.rs:26:18 | -LL | fn foo(self: Rc>); //~ ERROR arbitrary `self` types are unstable - | ^^^^^^^^^^^^^ +LL | fn foo(self: Ptr); //~ ERROR `Ptr` cannot be used as the type of `self` without + | ^^^^^^^^^ | = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box` -error[E0658]: arbitrary `self` types are unstable (see issue #44874) - --> $DIR/feature-gate-arbitrary-self-types.rs:20:18 +error[E0658]: `Ptr` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874) + --> $DIR/feature-gate-arbitrary-self-types.rs:32:18 | -LL | fn foo(self: Rc>) {} //~ ERROR arbitrary `self` types are unstable - | ^^^^^^^^^^^^^ +LL | fn foo(self: Ptr) {} //~ ERROR `Ptr` cannot be used as the type of `self` without + | ^^^^^^^^^ | = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box` -error[E0658]: arbitrary `self` types are unstable (see issue #44874) - --> $DIR/feature-gate-arbitrary-self-types.rs:24:18 +error[E0658]: `std::boxed::Box>` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874) + --> $DIR/feature-gate-arbitrary-self-types.rs:36:18 | -LL | fn bar(self: Box>) {} //~ ERROR arbitrary `self` types are unstable - | ^^^^^^^^^^^^^ +LL | fn bar(self: Box>) {} //~ ERROR `std::boxed::Box>` cannot be used as the + | ^^^^^^^^^^^^^^ | = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box` diff --git a/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.rs b/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.rs index 29e51727edcfd..6d42460ba5684 100644 --- a/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.rs +++ b/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.rs @@ -12,17 +12,17 @@ struct Foo; impl Foo { fn foo(self: *const Self) {} - //~^ ERROR raw pointer `self` is unstable + //~^ ERROR `*const Foo` cannot be used as the type of `self` without } trait Bar { fn bar(self: *const Self); - //~^ ERROR raw pointer `self` is unstable + //~^ ERROR `*const Self` cannot be used as the type of `self` without } impl Bar for () { fn bar(self: *const Self) {} - //~^ ERROR raw pointer `self` is unstable + //~^ ERROR `*const ()` cannot be used as the type of `self` without } fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr b/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr index 5ed9a0f4ed040..b8cc7dee9867d 100644 --- a/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr +++ b/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr @@ -1,4 +1,4 @@ -error[E0658]: raw pointer `self` is unstable (see issue #44874) +error[E0658]: `*const Self` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874) --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:19:18 | LL | fn bar(self: *const Self); @@ -7,7 +7,7 @@ LL | fn bar(self: *const Self); = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box` -error[E0658]: raw pointer `self` is unstable (see issue #44874) +error[E0658]: `*const Foo` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874) --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:14:18 | LL | fn foo(self: *const Self) {} @@ -16,7 +16,7 @@ LL | fn foo(self: *const Self) {} = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box` -error[E0658]: raw pointer `self` is unstable (see issue #44874) +error[E0658]: `*const ()` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874) --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:24:18 | LL | fn bar(self: *const Self) {}