diff --git a/crates/objc2/Cargo.toml b/crates/objc2/Cargo.toml index 2c5591e65..b6b4d2017 100644 --- a/crates/objc2/Cargo.toml +++ b/crates/objc2/Cargo.toml @@ -85,6 +85,10 @@ unstable-autoreleasesafe = [] # Additionally, the message sending improvements is not yet implemented. unstable-apple-new = [] +# Uses the nightly arbitrary_self_types feature to make initialization more +# ergonomic. +unstable-arbitrary-self-types = [] + # Deprecated; this is the default on Apple platforms, and not applicable on other platforms. apple = [] diff --git a/crates/objc2/src/lib.rs b/crates/objc2/src/lib.rs index 3a969c112..4ff7ab12e 100644 --- a/crates/objc2/src/lib.rs +++ b/crates/objc2/src/lib.rs @@ -151,6 +151,10 @@ feature = "unstable-autoreleasesafe", feature(negative_impls, auto_traits) )] +#![cfg_attr( + feature = "unstable-arbitrary-self-types", + feature(arbitrary_self_types) +)] // Note: `doc_notable_trait` doesn't really make sense for us, it's only shown // for functions returning a specific trait. #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg, doc_cfg_hide))] diff --git a/crates/objc2/src/rc/allocated_partial_init.rs b/crates/objc2/src/rc/allocated_partial_init.rs index d6f2f2f39..4b819d25e 100644 --- a/crates/objc2/src/rc/allocated_partial_init.rs +++ b/crates/objc2/src/rc/allocated_partial_init.rs @@ -56,6 +56,13 @@ pub struct Allocated { } // Explicitly don't implement `Deref`, `Message` nor `RefEncode`. +// +// We do want to implement `Receiver` though, to allow the user to type +// `self: Allocated`. +#[cfg(feature = "unstable-arbitrary-self-types")] +impl core::ops::Receiver for Allocated { + type Target = T; +} impl Allocated { /// # Safety @@ -349,4 +356,20 @@ mod tests { let obj: Allocated = unsafe { Allocated::new(ptr::null_mut()) }; let _ = obj.set_ivars(()); } + + #[test] + #[cfg(feature = "unstable-arbitrary-self-types")] + fn arbitrary_self_types() { + use crate::rc::Retained; + use crate::{extern_methods, AllocAnyThread}; + + extern_methods!( + unsafe impl RcTestObject { + #[method_id(init)] + fn init_with_self(self: Allocated) -> Retained; + } + ); + + let _ = RcTestObject::alloc().init_with_self(); + } }