Skip to content
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

Stabilize Rc, Arc and Pin as method receivers #56805

Merged
merged 3 commits into from
Dec 22, 2018
Merged
Show file tree
Hide file tree
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
Expand Up @@ -77,7 +77,9 @@ use core::iter::{Iterator, FromIterator, 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};

Expand Down Expand Up @@ -583,6 +585,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;
Expand Down
1 change: 1 addition & 0 deletions src/liballoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
5 changes: 4 additions & 1 deletion src/liballoc/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,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};
Expand Down Expand Up @@ -813,6 +813,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`.
Expand Down
5 changes: 4 additions & 1 deletion src/liballoc/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -767,6 +767,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`.
///
Expand Down
16 changes: 16 additions & 0 deletions src/libcore/ops/deref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,19 @@ pub trait DerefMut: Deref {
impl<T: ?Sized> DerefMut for &mut T {
fn deref_mut(&mut self) -> &mut T { *self }
}

/// 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")]
#[doc(hidden)]
pub trait Receiver {
// 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
Expand Up @@ -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;

Expand Down
5 changes: 4 additions & 1 deletion src/libcore/pin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,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;
Expand Down Expand Up @@ -302,6 +302,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 {
Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,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;
Expand Down
164 changes: 120 additions & 44 deletions src/librustc_typeck/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ 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::{self, Lift, Ty, TyCtxt, TyKind, GenericParamDefKind, TypeFoldable, ToPredicate};
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;
Expand Down Expand Up @@ -749,72 +748,149 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
&ty::Binder::bind(self_ty)
);

let self_arg_ty = sig.inputs()[0];
let receiver_ty = sig.inputs()[0];

let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver);
let self_arg_ty = fcx.normalize_associated_types_in(span, &self_arg_ty);
let self_arg_ty = fcx.tcx.liberate_late_bound_regions(
let receiver_ty = fcx.normalize_associated_types_in(span, &receiver_ty);
let receiver_ty = fcx.tcx.liberate_late_bound_regions(
method.def_id,
&ty::Binder::bind(self_arg_ty)
&ty::Binder::bind(receiver_ty)
);

let mut autoderef = fcx.autoderef(span, self_arg_ty).include_raw_pointers();
if fcx.tcx.features().arbitrary_self_types {
if !receiver_is_valid(fcx, span, receiver_ty, self_ty, true) {
// report error, arbitrary_self_types was enabled
fcx.tcx.sess.diagnostic().mut_span_err(
span, &format!("invalid method receiver type: {:?}", receiver_ty)
).note("type of `self` must be `Self` or a type that dereferences to it")
.help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
.code(DiagnosticId::Error("E0307".into()))
.emit();
}
} else {
if !receiver_is_valid(fcx, span, receiver_ty, self_ty, false) {
if receiver_is_valid(fcx, span, receiver_ty, self_ty, true) {
// report error, would have worked with arbitrary_self_types
feature_gate::feature_err(
&fcx.tcx.sess.parse_sess,
"arbitrary_self_types",
span,
GateIssue::Language,
&format!(
"`{}` cannot be used as the type of `self` without \
the `arbitrary_self_types` feature",
receiver_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 method receiver type: {:?}", receiver_ty)
).note("type must be `Self` or a type that dereferences to it")
.help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
.code(DiagnosticId::Error("E0307".into()))
.emit();
}
}
}
}

/// returns true if `receiver_ty` would be considered a valid receiver type for `self_ty`. If
/// `arbitrary_self_types` is enabled, `receiver_ty` must transitively deref to `self_ty`, possibly
/// through a `*const/mut T` raw pointer. If the feature is not enabled, the requirements are more
/// strict: `receiver_ty` must implement `Receiver` and directly implement `Deref<Target=self_ty>`.
///
/// NB: there are cases this function returns `true` but causes an error to be emitted,
/// particularly when `receiver_ty` derefs to a type that is the same as `self_ty` but has the
/// wrong lifetime. Be careful of this if you are calling this function speculatively.
fn receiver_is_valid<'fcx, 'tcx, 'gcx>(
fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
span: Span,
receiver_ty: Ty<'tcx>,
self_ty: Ty<'tcx>,
arbitrary_self_types_enabled: bool,
) -> bool {
let cause = fcx.cause(span, traits::ObligationCauseCode::MethodReceiver);

let can_eq_self = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok();

// `self: Self` is always valid
if can_eq_self(receiver_ty) {
if let Some(mut err) = fcx.demand_eqtype_with_origin(&cause, self_ty, receiver_ty) {
err.emit();
}
return true
}

let mut autoderef = fcx.autoderef(span, receiver_ty);

// the `arbitrary_self_types` feature allows raw pointer receivers like `self: *const Self`
if arbitrary_self_types_enabled {
autoderef = autoderef.include_raw_pointers();
}

// the first type is `receiver_ty`, which we know its not equal to `self_ty`. skip it.
autoderef.next();

// keep dereferencing `receiver_ty` until we get to `self_ty`
loop {
if let Some((potential_self_ty, _)) = autoderef.next() {
debug!("check_method_receiver: potential self type `{:?}` to match `{:?}`",
debug!("receiver_is_valid: potential self type `{:?}` to match `{:?}`",
potential_self_ty, self_ty);

if fcx.infcx.can_eq(fcx.param_env, self_ty, potential_self_ty).is_ok() {
if can_eq_self(potential_self_ty) {
autoderef.finalize(fcx);

if let Some(mut err) = fcx.demand_eqtype_with_origin(
&cause, self_ty, potential_self_ty) {
&cause, self_ty, potential_self_ty
) {
err.emit();
}

break
}
} else {
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();
return
debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`",
receiver_ty, self_ty);
return false
}

// without the `arbitrary_self_types` feature, `receiver_ty` must directly deref to
// `self_ty`. Enforce this by only doing one iteration of the loop
if !arbitrary_self_types_enabled {
return false
}
}

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);
// without `feature(arbitrary_self_types)`, we require that `receiver_ty` implements `Receiver`
if !arbitrary_self_types_enabled {
let trait_def_id = match fcx.tcx.lang_items().receiver_trait() {
Some(did) => did,
None => {
debug!("receiver_is_valid: missing Receiver trait");
return false
}
};

if !fcx.tcx.features().arbitrary_self_types {
match self_kind {
ExplicitSelf::ByValue |
ExplicitSelf::ByReference(_, _) |
ExplicitSelf::ByBox => (),
let trait_ref = ty::TraitRef{
def_id: trait_def_id,
substs: fcx.tcx.mk_substs_trait(receiver_ty, &[]),
};

ExplicitSelf::ByRawPointer(_) => {
feature_gate::feature_err(
&fcx.tcx.sess.parse_sess,
"arbitrary_self_types",
span,
GateIssue::Language,
"raw pointer `self` is unstable")
.help("consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`")
.emit();
}
let obligation = traits::Obligation::new(
cause.clone(),
fcx.param_env,
trait_ref.to_predicate()
);

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();
}
if !fcx.predicate_must_hold(&obligation) {
debug!("receiver_is_valid: type `{:?}` does not implement `Receiver` trait",
receiver_ty);
return false
}
}

true
}

fn check_variances_for_type_defn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
Expand Down
9 changes: 8 additions & 1 deletion src/test/run-pass/arbitrary_self_types_stdlib_pointers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]

Expand All @@ -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 {
Expand All @@ -38,6 +38,9 @@ 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
}
}

fn main() {
Expand All @@ -53,4 +56,8 @@ 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());
}
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
Expand Up @@ -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() {}
Loading