Skip to content

stabilize Rc, Arc and Pin as method receivers #55880

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/liballoc/boxed.rs
Original file line number Diff line number Diff line change
@@ -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<T: ?Sized> DerefMut for Box<T> {
}
}

#[unstable(feature = "receiver_trait", issue = "0")]
impl<T: ?Sized> Receiver for Box<T> {}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator + ?Sized> Iterator for Box<I> {
type Item = I::Item;
1 change: 1 addition & 0 deletions src/liballoc/lib.rs
Original file line number Diff line number Diff line change
@@ -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)]
5 changes: 4 additions & 1 deletion src/liballoc/rc.rs
Original file line number Diff line number Diff line change
@@ -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<T: ?Sized> Deref for Rc<T> {
}
}

#[unstable(feature = "receiver_trait", issue = "0")]
impl<T: ?Sized> Receiver for Rc<T> {}

#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc<T> {
/// Drops the `Rc`.
5 changes: 4 additions & 1 deletion src/liballoc/sync.rs
Original file line number Diff line number Diff line change
@@ -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<T: ?Sized> Deref for Arc<T> {
}
}

#[unstable(feature = "receiver_trait", issue = "0")]
impl<T: ?Sized> Receiver for Arc<T> {}

impl<T: Clone> Arc<T> {
/// Makes a mutable reference into the given `Arc`.
///
15 changes: 15 additions & 0 deletions src/libcore/ops/deref.rs
Original file line number Diff line number Diff line change
@@ -177,3 +177,18 @@ pub trait DerefMut: Deref {
impl<T: ?Sized> 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<T>`,
/// `Rc<T>`, `&T`, and `Pin<P>`.
#[cfg_attr(not(stage0), lang = "receiver")]
#[unstable(feature = "receiver_trait", issue = "0")]
pub trait Receiver: Deref {
// Empty.
}

#[unstable(feature = "receiver_trait", issue = "0")]
impl<T: ?Sized> Receiver for &T {}

#[unstable(feature = "receiver_trait", issue = "0")]
impl<T: ?Sized> Receiver for &mut T {}
3 changes: 3 additions & 0 deletions src/libcore/ops/mod.rs
Original file line number Diff line number Diff line change
@@ -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;

5 changes: 4 additions & 1 deletion src/libcore/pin.rs
Original file line number Diff line number Diff line change
@@ -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<P: Receiver> Receiver for Pin<P> {}

#[unstable(feature = "pin", issue = "49150")]
impl<P: fmt::Debug> fmt::Debug for Pin<P> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1 change: 1 addition & 0 deletions src/librustc/middle/lang_items.rs
Original file line number Diff line number Diff line change
@@ -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;
31 changes: 30 additions & 1 deletion src/librustc_typeck/check/autoderef.rs
Original file line number Diff line number Diff line change
@@ -38,6 +38,7 @@ pub struct Autoderef<'a, 'gcx: 'tcx, 'tcx: 'a> {
obligations: Vec<traits::PredicateObligation<'tcx>>,
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<T>`
/// 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,
}
}
100 changes: 65 additions & 35 deletions src/librustc_typeck/check/wfcheck.rs
Original file line number Diff line number Diff line change
@@ -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<Self>`")
.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<Self>`")
.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<Self>`")
.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<Self>`")
.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<Ty<'tcx>> {
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
}
}
}
19 changes: 18 additions & 1 deletion src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs
Original file line number Diff line number Diff line change
@@ -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<Self>) -> i64;
fn by_pin_mut(self: Pin<&mut Self>) -> i64;
fn by_pin_box(self: Pin<Box<Self>>) -> i64;
fn by_pin_pin_pin_ref(self: Pin<Pin<Pin<&Self>>>) -> i64;
}

impl Trait for i64 {
@@ -38,6 +38,17 @@ impl Trait for i64 {
fn by_pin_box(self: Pin<Box<Self>>) -> i64 {
*self
}
fn by_pin_pin_pin_ref(self: Pin<Pin<Pin<&Self>>>) -> i64 {
*self
}
}

struct Foo;

impl Foo {
fn by_box_rc(self: Box<Rc<Self>>) -> i32 {
11
}
}

fn main() {
@@ -53,4 +64,10 @@ fn main() {

let pin_box = Into::<Pin<Box<i64>>>::into(Box::new(4i64)) as Pin<Box<dyn Trait>>;
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<Pin<Pin<&dyn Trait>>>;
assert_eq!(5, pin_pin_pin_ref.by_pin_pin_pin_ref());

assert_eq!(11, Box::new(Rc::new(Foo)).by_box_rc());
}
20 changes: 16 additions & 4 deletions src/test/ui/feature-gates/feature-gate-arbitrary-self-types.rs
Original file line number Diff line number Diff line change
@@ -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<T: ?Sized>(Box<T>);

impl<T: ?Sized> Deref for Ptr<T> {
type Target = T;

fn deref(&self) -> &T {
&*self.0
}
}

trait Foo {
fn foo(self: Rc<Box<Self>>); //~ ERROR arbitrary `self` types are unstable
fn foo(self: Ptr<Self>); //~ ERROR `Ptr<Self>` cannot be used as the type of `self` without
}

struct Bar;

impl Foo for Bar {
fn foo(self: Rc<Box<Self>>) {} //~ ERROR arbitrary `self` types are unstable
fn foo(self: Ptr<Self>) {} //~ ERROR `Ptr<Bar>` cannot be used as the type of `self` without
}

impl Bar {
fn bar(self: Box<Rc<Self>>) {} //~ ERROR arbitrary `self` types are unstable
fn bar(self: Box<Ptr<Self>>) {} //~ ERROR `std::boxed::Box<Ptr<Bar>>` cannot be used as the
}

fn main() {}
24 changes: 12 additions & 12 deletions src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr
Original file line number Diff line number Diff line change
@@ -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<Self>` 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<Box<Self>>); //~ ERROR arbitrary `self` types are unstable
| ^^^^^^^^^^^^^
LL | fn foo(self: Ptr<Self>); //~ ERROR `Ptr<Self>` 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<Self>`

error[E0658]: arbitrary `self` types are unstable (see issue #44874)
--> $DIR/feature-gate-arbitrary-self-types.rs:20:18
error[E0658]: `Ptr<Bar>` 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<Box<Self>>) {} //~ ERROR arbitrary `self` types are unstable
| ^^^^^^^^^^^^^
LL | fn foo(self: Ptr<Self>) {} //~ ERROR `Ptr<Bar>` 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<Self>`

error[E0658]: arbitrary `self` types are unstable (see issue #44874)
--> $DIR/feature-gate-arbitrary-self-types.rs:24:18
error[E0658]: `std::boxed::Box<Ptr<Bar>>` 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<Rc<Self>>) {} //~ ERROR arbitrary `self` types are unstable
| ^^^^^^^^^^^^^
LL | fn bar(self: Box<Ptr<Self>>) {} //~ ERROR `std::boxed::Box<Ptr<Bar>>` 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<Self>`
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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<Self>`

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<Self>`

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) {}