Skip to content

Commit

Permalink
Arbitrary self types v2: (unused) Receiver trait
Browse files Browse the repository at this point in the history
This commit contains a new Receiver trait, which is the basis for the
Arbitrary Self Types v2 RFC. This allows smart pointers to be method
receivers even if they're not Deref.

This is currently unused by the compiler - a subsequent PR will start to
use this for method resolution if the arbitrary_self_types feature gate
is enabled. This is being landed first simply to make review
simpler: if people feel this should all be in an atomic PR let me know.

This is a part of the arbitrary self types v2 project,
rust-lang/rfcs#3519
rust-lang#44874

r? @wesleywiser
  • Loading branch information
adetaylor committed Oct 25, 2024
1 parent f61306d commit d6b8731
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 2 deletions.
2 changes: 2 additions & 0 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,8 @@ language_item_table! {
DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait, GenericRequirement::Exact(0);
DerefPure, sym::deref_pure, deref_pure_trait, Target::Trait, GenericRequirement::Exact(0);
DerefTarget, sym::deref_target, deref_target, Target::AssocTy, GenericRequirement::None;
Receiver, sym::receiver, receiver_trait, Target::Trait, GenericRequirement::None;
ReceiverTarget, sym::receiver_target, receiver_target, Target::AssocTy, GenericRequirement::None;
LegacyReceiver, sym::legacy_receiver, legacy_receiver_trait, Target::Trait, GenericRequirement::None;

Fn, kw::Fn, fn_trait, Target::Trait, GenericRequirement::Exact(1);
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1574,6 +1574,8 @@ symbols! {
readonly,
realloc,
reason,
receiver,
receiver_target,
recursion_limit,
reexport_test_harness_main,
ref_pat_eat_one_layer_2024,
Expand Down
90 changes: 88 additions & 2 deletions library/core/src/ops/deref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,14 +294,100 @@ unsafe impl<T: ?Sized> DerefPure for &T {}
#[unstable(feature = "deref_pure_trait", issue = "87121")]
unsafe impl<T: ?Sized> DerefPure for &mut T {}

/// Indicates that a struct can be used as a method receiver.
/// That is, a type can use this type as a type of `self`, like this:
/// ```
/// use std::ops::Receiver;
///
/// struct SmartPointer<T>(T);
///
/// impl<T> Receiver for SmartPointer<T> {
/// type Target = T;
/// }
///
/// struct MyContainedType;
///
/// impl MyContainedType {
/// fn method(self: MySmartPointer<Self>) {
/// // ...
/// }
/// }
///
/// fn main() {
/// let ptr = SmartPointer(MyContainedType);
/// ptr.method();
/// }
/// ```
/// This trait is blanket implemented for any type which implements
/// [`Deref`], which includes stdlib pointer types like `Box<T>`,`Rc<T>`, `&T`,
/// and `Pin<P>`. For that reason, it's relatively rare to need to
/// implement this directly. You'll typically do this only if you need
/// to implement a smart pointer type which can't implement [`Deref`]; perhaps
/// because you're interfacing with another programming language and can't
/// guarantee that references comply with Rust's aliasing rules.
///
/// When looking for method candidates, Rust will explore a chain of possible
/// `Receiver`s, so for example each of the following methods work:
/// ```
/// use std::boxed::Box;
/// use std::rc::Rc;
///
/// // Both `Box` and `Rc`` (indirectly) implement Receiver
///
/// struct MyContainedType;
///
/// fn main() {
/// let t = Rc::new(Box::new(MyContainedType));
/// t.method_a();
/// t.method_b();
/// t.method_c();
/// t.method_d();
/// }
///
/// impl MyContainedType {
/// fn method_a(self) {
///
/// }
/// fn method_b(&self) {
///
/// }
/// fn method_c(self: Box<Self>) {
///
/// }
/// fn method_d(self: Rc<Box<Self>>) {
///
/// }
/// }
/// ```
#[lang = "receiver"]
#[cfg(not(bootstrap))]
#[unstable(feature = "arbitrary_self_types", issue = "44874")]
pub trait Receiver {
/// The target type on which the method may be called.
#[cfg(not(bootstrap))]
#[rustc_diagnostic_item = "receiver_target"]
#[lang = "receiver_target"]
#[unstable(feature = "arbitrary_self_types", issue = "44874")]
type Target: ?Sized;
}

#[cfg(not(bootstrap))]
#[unstable(feature = "arbitrary_self_types", issue = "44874")]
impl<P: ?Sized, T: ?Sized> Receiver for P
where
P: Deref<Target = T>,
{
type Target = T;
}

/// 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>`.
///
/// This trait will shortly be removed and replaced with a more generic
/// facility based around the current "arbitrary self types" unstable feature.
/// That new facility will use a replacement trait called `Receiver` which is
/// why this is now named `LegacyReceiver`.
/// That new facility will use the replacement trait above called `Receiver`
/// which is why this is now named `LegacyReceiver`.
#[cfg_attr(bootstrap, lang = "receiver")]
#[cfg_attr(not(bootstrap), lang = "legacy_receiver")]
#[unstable(feature = "legacy_receiver_trait", issue = "none")]
Expand Down
3 changes: 3 additions & 0 deletions library/core/src/ops/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,9 @@ pub use self::coroutine::{Coroutine, CoroutineState};
pub use self::deref::DerefPure;
#[unstable(feature = "legacy_receiver_trait", issue = "none")]
pub use self::deref::LegacyReceiver;
#[unstable(feature = "arbitrary_self_types", issue = "44874")]
#[cfg(not(bootstrap))]
pub use self::deref::Receiver;
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::deref::{Deref, DerefMut};
#[stable(feature = "rust1", since = "1.0.0")]
Expand Down

0 comments on commit d6b8731

Please sign in to comment.