Skip to content

Commit 153f5a7

Browse files
committed
Stabilize Rc, Arc and Pin as method receivers
This lets you write methods using `self: Rc<Self>`, `self: Arc<Self>`, `self: Pin<&mut Self>`, `self: Pin<Box<Self>`, and other combinations involving `Pin` and another stdlib receiver type, without needing the `arbitrary_self_types`. Other user-created receiver types can be used, but they still require the feature flag to use. This is implemented by introducing a new trait, `Receiver`, which the method receiver's type must implement if the `arbitrary_self_types` feature is not enabled. To keep composed receiver types such as `&Arc<Self>` unstable, the receiver type is also required to implement `Deref<Target=Self>` when the feature flag is not enabled. This lets you use `self: Rc<Self>` and `self: Arc<Self>` in stable Rust, which was not allowed previously. It was agreed that they would be stabilized in #55786. `self: Pin<&Self>` and other pinned receiver types do not require the `arbitrary_self_types` feature, but they cannot be used on stable because `Pin` still requires the `pin` feature.
1 parent daa8792 commit 153f5a7

16 files changed

+250
-91
lines changed

src/liballoc/boxed.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ use core::iter::{Iterator, FromIterator, FusedIterator};
7777
use core::marker::{Unpin, Unsize};
7878
use core::mem;
7979
use core::pin::Pin;
80-
use core::ops::{CoerceUnsized, DispatchFromDyn, Deref, DerefMut, Generator, GeneratorState};
80+
use core::ops::{
81+
CoerceUnsized, DispatchFromDyn, Deref, DerefMut, Receiver, Generator, GeneratorState
82+
};
8183
use core::ptr::{self, NonNull, Unique};
8284
use core::task::{LocalWaker, Poll};
8385

@@ -583,6 +585,9 @@ impl<T: ?Sized> DerefMut for Box<T> {
583585
}
584586
}
585587

588+
#[unstable(feature = "receiver_trait", issue = "0")]
589+
impl<T: ?Sized> Receiver for Box<T> {}
590+
586591
#[stable(feature = "rust1", since = "1.0.0")]
587592
impl<I: Iterator + ?Sized> Iterator for Box<I> {
588593
type Item = I::Item;

src/liballoc/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
#![feature(ptr_internals)]
105105
#![feature(ptr_offset_from)]
106106
#![feature(rustc_attrs)]
107+
#![feature(receiver_trait)]
107108
#![feature(specialization)]
108109
#![feature(split_ascii_whitespace)]
109110
#![feature(staged_api)]

src/liballoc/rc.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ use core::intrinsics::abort;
253253
use core::marker;
254254
use core::marker::{Unpin, Unsize, PhantomData};
255255
use core::mem::{self, align_of_val, forget, size_of_val};
256-
use core::ops::Deref;
256+
use core::ops::{Deref, Receiver};
257257
use core::ops::{CoerceUnsized, DispatchFromDyn};
258258
use core::pin::Pin;
259259
use core::ptr::{self, NonNull};
@@ -813,6 +813,9 @@ impl<T: ?Sized> Deref for Rc<T> {
813813
}
814814
}
815815

816+
#[unstable(feature = "receiver_trait", issue = "0")]
817+
impl<T: ?Sized> Receiver for Rc<T> {}
818+
816819
#[stable(feature = "rust1", since = "1.0.0")]
817820
unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc<T> {
818821
/// Drops the `Rc`.

src/liballoc/sync.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use core::fmt;
2424
use core::cmp::Ordering;
2525
use core::intrinsics::abort;
2626
use core::mem::{self, align_of_val, size_of_val};
27-
use core::ops::Deref;
27+
use core::ops::{Deref, Receiver};
2828
use core::ops::{CoerceUnsized, DispatchFromDyn};
2929
use core::pin::Pin;
3030
use core::ptr::{self, NonNull};
@@ -767,6 +767,9 @@ impl<T: ?Sized> Deref for Arc<T> {
767767
}
768768
}
769769

770+
#[unstable(feature = "receiver_trait", issue = "0")]
771+
impl<T: ?Sized> Receiver for Arc<T> {}
772+
770773
impl<T: Clone> Arc<T> {
771774
/// Makes a mutable reference into the given `Arc`.
772775
///

src/libcore/ops/deref.rs

+16
Original file line numberDiff line numberDiff line change
@@ -177,3 +177,19 @@ pub trait DerefMut: Deref {
177177
impl<T: ?Sized> DerefMut for &mut T {
178178
fn deref_mut(&mut self) -> &mut T { *self }
179179
}
180+
181+
/// Indicates that a struct can be used as a method receiver, without the
182+
/// `arbitrary_self_types` feature. This is implemented by stdlib pointer types like `Box<T>`,
183+
/// `Rc<T>`, `&T`, and `Pin<P>`.
184+
#[cfg_attr(not(stage0), lang = "receiver")]
185+
#[unstable(feature = "receiver_trait", issue = "0")]
186+
#[doc(hidden)]
187+
pub trait Receiver {
188+
// Empty.
189+
}
190+
191+
#[unstable(feature = "receiver_trait", issue = "0")]
192+
impl<T: ?Sized> Receiver for &T {}
193+
194+
#[unstable(feature = "receiver_trait", issue = "0")]
195+
impl<T: ?Sized> Receiver for &mut T {}

src/libcore/ops/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,9 @@ pub use self::bit::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssig
178178
#[stable(feature = "rust1", since = "1.0.0")]
179179
pub use self::deref::{Deref, DerefMut};
180180

181+
#[unstable(feature = "receiver_trait", issue = "0")]
182+
pub use self::deref::Receiver;
183+
181184
#[stable(feature = "rust1", since = "1.0.0")]
182185
pub use self::drop::Drop;
183186

src/libcore/pin.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@
101101

102102
use fmt;
103103
use marker::Sized;
104-
use ops::{Deref, DerefMut, CoerceUnsized, DispatchFromDyn};
104+
use ops::{Deref, DerefMut, Receiver, CoerceUnsized, DispatchFromDyn};
105105

106106
#[doc(inline)]
107107
pub use marker::Unpin;
@@ -302,6 +302,9 @@ where
302302
}
303303
}
304304

305+
#[unstable(feature = "receiver_trait", issue = "0")]
306+
impl<P: Receiver> Receiver for Pin<P> {}
307+
305308
#[unstable(feature = "pin", issue = "49150")]
306309
impl<P: fmt::Debug> fmt::Debug for Pin<P> {
307310
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

src/librustc/middle/lang_items.rs

+1
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ language_item_table! {
301301

302302
DerefTraitLangItem, "deref", deref_trait, Target::Trait;
303303
DerefMutTraitLangItem, "deref_mut", deref_mut_trait, Target::Trait;
304+
ReceiverTraitLangItem, "receiver", receiver_trait, Target::Trait;
304305

305306
FnTraitLangItem, "fn", fn_trait, Target::Trait;
306307
FnMutTraitLangItem, "fn_mut", fn_mut_trait, Target::Trait;

src/librustc_typeck/check/wfcheck.rs

+138-47
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,8 @@ use constrained_type_params::{identify_constrained_type_params, Parameter};
1313

1414
use hir::def_id::DefId;
1515
use rustc::traits::{self, ObligationCauseCode};
16-
use rustc::ty::{self, Lift, Ty, TyCtxt, TyKind, GenericParamDefKind, TypeFoldable};
16+
use rustc::ty::{self, Lift, Ty, TyCtxt, TyKind, GenericParamDefKind, TypeFoldable, ToPredicate};
1717
use rustc::ty::subst::{Subst, Substs};
18-
use rustc::ty::util::ExplicitSelf;
1918
use rustc::util::nodemap::{FxHashSet, FxHashMap};
2019
use rustc::middle::lang_items;
2120
use rustc::infer::opaque_types::may_define_existential_type;
@@ -749,72 +748,164 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
749748
&ty::Binder::bind(self_ty)
750749
);
751750

752-
let self_arg_ty = sig.inputs()[0];
751+
let receiver_ty = sig.inputs()[0];
753752

754-
let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver);
755-
let self_arg_ty = fcx.normalize_associated_types_in(span, &self_arg_ty);
756-
let self_arg_ty = fcx.tcx.liberate_late_bound_regions(
753+
let receiver_ty = fcx.normalize_associated_types_in(span, &receiver_ty);
754+
let receiver_ty = fcx.tcx.liberate_late_bound_regions(
757755
method.def_id,
758-
&ty::Binder::bind(self_arg_ty)
756+
&ty::Binder::bind(receiver_ty)
759757
);
760758

761-
let mut autoderef = fcx.autoderef(span, self_arg_ty).include_raw_pointers();
762-
763-
loop {
764-
if let Some((potential_self_ty, _)) = autoderef.next() {
765-
debug!("check_method_receiver: potential self type `{:?}` to match `{:?}`",
766-
potential_self_ty, self_ty);
767-
768-
if fcx.infcx.can_eq(fcx.param_env, self_ty, potential_self_ty).is_ok() {
769-
autoderef.finalize(fcx);
770-
if let Some(mut err) = fcx.demand_eqtype_with_origin(
771-
&cause, self_ty, potential_self_ty) {
772-
err.emit();
773-
}
774-
break
775-
}
776-
} else {
759+
if fcx.tcx.features().arbitrary_self_types {
760+
if !receiver_is_valid(fcx, span, receiver_ty, self_ty, true) {
761+
// report error, arbitrary_self_types was enabled
777762
fcx.tcx.sess.diagnostic().mut_span_err(
778-
span, &format!("invalid `self` type: {:?}", self_arg_ty))
779-
.note(&format!("type must be `{:?}` or a type that dereferences to it", self_ty))
763+
span, &format!("invalid `self` type: {:?}", receiver_ty)
764+
).note(&format!("type must be `{:?}` or a type that dereferences to it", self_ty))
780765
.help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
781766
.code(DiagnosticId::Error("E0307".into()))
782767
.emit();
783-
return
784768
}
785-
}
786-
787-
let is_self_ty = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok();
788-
let self_kind = ExplicitSelf::determine(self_arg_ty, is_self_ty);
789-
790-
if !fcx.tcx.features().arbitrary_self_types {
791-
match self_kind {
792-
ExplicitSelf::ByValue |
793-
ExplicitSelf::ByReference(_, _) |
794-
ExplicitSelf::ByBox => (),
795-
796-
ExplicitSelf::ByRawPointer(_) => {
769+
} else {
770+
if !receiver_is_valid(fcx, span, receiver_ty, self_ty, false) {
771+
if receiver_is_valid(fcx, span, receiver_ty, self_ty, true) {
772+
// report error, would have worked with arbitrary_self_types
797773
feature_gate::feature_err(
798774
&fcx.tcx.sess.parse_sess,
799775
"arbitrary_self_types",
800776
span,
801777
GateIssue::Language,
802-
"raw pointer `self` is unstable")
778+
&format!(
779+
"`{}` cannot be used as the type of `self` without \
780+
the `arbitrary_self_types` feature",
781+
receiver_ty,
782+
),
783+
).help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
784+
.emit();
785+
} else {
786+
// report error, would not have worked with arbitrary_self_types
787+
fcx.tcx.sess.diagnostic().mut_span_err(
788+
span, &format!("invalid `self` type: {:?}", receiver_ty)
789+
).note(&format!("type must be `{:?}` or a type that dereferences to it", self_ty))
803790
.help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
791+
.code(DiagnosticId::Error("E0307".into()))
804792
.emit();
805793
}
794+
}
795+
}
796+
}
806797

807-
ExplicitSelf::Other => {
808-
feature_gate::feature_err(
809-
&fcx.tcx.sess.parse_sess,
810-
"arbitrary_self_types",
811-
span,
812-
GateIssue::Language,"arbitrary `self` types are unstable")
813-
.help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
814-
.emit();
798+
fn receiver_is_valid<'fcx, 'tcx, 'gcx>(
799+
fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
800+
span: Span,
801+
receiver_ty: Ty<'tcx>,
802+
self_ty: Ty<'tcx>,
803+
arbitrary_self_types_enabled: bool,
804+
) -> bool {
805+
let cause = fcx.cause(span, traits::ObligationCauseCode::MethodReceiver);
806+
807+
let can_eq_self = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok();
808+
809+
if can_eq_self(receiver_ty) {
810+
if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, self_ty, receiver_ty) {
811+
err.emit();
812+
}
813+
return true
814+
}
815+
816+
let mut autoderef = fcx.autoderef(span, receiver_ty);
817+
818+
if arbitrary_self_types_enabled {
819+
autoderef = autoderef.include_raw_pointers();
820+
}
821+
822+
// skip the first type, we know its not equal to `self_ty`
823+
autoderef.next();
824+
825+
let potential_self_ty = loop {
826+
if let Some((potential_self_ty, _)) = autoderef.next() {
827+
debug!("receiver_is_valid: potential self type `{:?}` to match `{:?}`",
828+
potential_self_ty, self_ty);
829+
830+
if can_eq_self(potential_self_ty) {
831+
break potential_self_ty
832+
}
833+
} else {
834+
debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`",
835+
receiver_ty, self_ty);
836+
return false
837+
}
838+
};
839+
840+
if !arbitrary_self_types_enabled {
841+
// check that receiver_ty: Receiver<Target=self_ty>
842+
843+
let receiver_trait_def_id = match fcx.tcx.lang_items().receiver_trait() {
844+
Some(did) => did,
845+
None => {
846+
debug!("receiver_is_valid: missing Receiver trait");
847+
return false
815848
}
849+
};
850+
851+
let receiver_trait_ref = ty::TraitRef{
852+
def_id: receiver_trait_def_id,
853+
substs: fcx.tcx.mk_substs_trait(receiver_ty, &[]),
854+
};
855+
856+
let receiver_obligation = traits::Obligation::new(
857+
cause.clone(),
858+
fcx.param_env,
859+
receiver_trait_ref.to_predicate()
860+
);
861+
862+
if !fcx.predicate_must_hold(&receiver_obligation) {
863+
debug!("receiver_is_valid: type `{:?}` does not implement `Receiver` trait",
864+
receiver_ty);
865+
return false
866+
}
867+
868+
let deref_trait_def_id = match fcx.tcx.lang_items().deref_trait() {
869+
Some(did) => did,
870+
None => {
871+
debug!("receiver_is_valid: missing Deref trait");
872+
return false
873+
}
874+
};
875+
876+
let deref_trait_ref = ty::TraitRef {
877+
def_id: deref_trait_def_id,
878+
substs: fcx.tcx.mk_substs_trait(receiver_ty, &[]),
879+
};
880+
881+
let projection_ty = ty::ProjectionTy::from_ref_and_name(
882+
fcx.tcx, deref_trait_ref, ast::Ident::from_str("Target")
883+
);
884+
885+
let projection_predicate = ty::Binder::dummy(ty::ProjectionPredicate {
886+
projection_ty, ty: self_ty
887+
}).to_predicate();
888+
889+
let deref_obligation = traits::Obligation::new(
890+
cause.clone(),
891+
fcx.param_env,
892+
projection_predicate,
893+
);
894+
895+
if !fcx.predicate_must_hold(&deref_obligation) {
896+
debug!("receiver_is_valid: type `{:?}` does not directly deref to `{:?}`",
897+
receiver_ty, self_ty);
898+
return false
816899
}
817900
}
901+
902+
if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, self_ty, potential_self_ty) {
903+
err.emit();
904+
}
905+
906+
autoderef.finalize(fcx);
907+
908+
true
818909
}
819910

820911
fn check_variances_for_type_defn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,

src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#![feature(arbitrary_self_types)]
1211
#![feature(pin)]
1312
#![feature(rustc_attrs)]
1413

@@ -23,6 +22,7 @@ trait Trait {
2322
fn by_arc(self: Arc<Self>) -> i64;
2423
fn by_pin_mut(self: Pin<&mut Self>) -> i64;
2524
fn by_pin_box(self: Pin<Box<Self>>) -> i64;
25+
fn by_pin_pin_pin_ref(self: Pin<Pin<Pin<&Self>>>) -> i64;
2626
}
2727

2828
impl Trait for i64 {
@@ -38,6 +38,9 @@ impl Trait for i64 {
3838
fn by_pin_box(self: Pin<Box<Self>>) -> i64 {
3939
*self
4040
}
41+
fn by_pin_pin_pin_ref(self: Pin<Pin<Pin<&Self>>>) -> i64 {
42+
*self
43+
}
4144
}
4245

4346
fn main() {
@@ -53,4 +56,8 @@ fn main() {
5356

5457
let pin_box = Into::<Pin<Box<i64>>>::into(Box::new(4i64)) as Pin<Box<dyn Trait>>;
5558
assert_eq!(4, pin_box.by_pin_box());
59+
60+
let value = 5i64;
61+
let pin_pin_pin_ref = Pin::new(Pin::new(Pin::new(&value))) as Pin<Pin<Pin<&dyn Trait>>>;
62+
assert_eq!(5, pin_pin_pin_ref.by_pin_pin_pin_ref());
5663
}

0 commit comments

Comments
 (0)