From 9bd6cc4bd72606dbad83fd8a971d0985e3119fd8 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Fri, 27 May 2022 00:10:47 +0200 Subject: [PATCH] Make Class no longer implement `Message` directly This is done so that: - `Id` is correct for all `T: Message` (currently `Id` is possible). - `ClassBuilder::add_method` doesn't accept functions that take `&Class` as the receiver. --- objc2/CHANGELOG.md | 3 +++ objc2/src/declare.rs | 23 ++++++++++++++++++++-- objc2/src/message/mod.rs | 26 +++++++++++++++++++++---- tests/ui/fn_ptr_reference_method.stderr | 4 ++-- tests/ui/msg_send_only_message.stderr | 5 +++-- 5 files changed, 51 insertions(+), 10 deletions(-) diff --git a/objc2/CHANGELOG.md b/objc2/CHANGELOG.md index 13e73e5ce..f68f37365 100644 --- a/objc2/CHANGELOG.md +++ b/objc2/CHANGELOG.md @@ -58,6 +58,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). If you previously used `*mut Object` or `&Object` as the receiver, message sending should work exactly as before. +* **BREAKING**: `Class` no longer implements `Message` (but it can still be + used as the receiver in `msg_send!`, so this is unlikely to break anything + in practice). ### Fixed * Properly sealed the `MessageArguments` trait (it already had a hidden diff --git a/objc2/src/declare.rs b/objc2/src/declare.rs index 49aa62fea..6427db18a 100644 --- a/objc2/src/declare.rs +++ b/objc2/src/declare.rs @@ -48,7 +48,7 @@ use crate::{ffi, Encode, EncodeArguments, Encoding, Message}; /// Types that can be used as the implementation of an Objective-C method. pub trait MethodImplementation { /// The callee type of the method. - type Callee: Message + ?Sized; + type Callee: ?Sized; /// The return type of the method. type Ret: Encode; /// The argument types of the method. @@ -75,6 +75,21 @@ macro_rules! method_decl_impl { } } ); + (@$s:ident, $r:ident, $f:ty, $($t:ident),*) => ( + impl<$r, $($t),*> MethodImplementation for $f + where + $r: Encode, + $($t: Encode,)* + { + type Callee = $s; + type Ret = $r; + type Args = ($($t,)*); + + fn imp(self) -> Imp { + unsafe { mem::transmute(self) } + } + } + ); ($($t:ident),*) => ( method_decl_impl!(-T, R, extern "C" fn(&T, Sel $(, $t)*) -> R, $($t),*); method_decl_impl!(-T, R, extern "C" fn(&mut T, Sel $(, $t)*) -> R, $($t),*); @@ -82,6 +97,10 @@ macro_rules! method_decl_impl { method_decl_impl!(-T, R, unsafe extern "C" fn(*mut T, Sel $(, $t)*) -> R, $($t),*); method_decl_impl!(-T, R, unsafe extern "C" fn(&T, Sel $(, $t)*) -> R, $($t),*); method_decl_impl!(-T, R, unsafe extern "C" fn(&mut T, Sel $(, $t)*) -> R, $($t),*); + + method_decl_impl!(@Class, R, extern "C" fn(&Class, Sel $(, $t)*) -> R, $($t),*); + method_decl_impl!(@Class, R, unsafe extern "C" fn(*const Class, Sel $(, $t)*) -> R, $($t),*); + method_decl_impl!(@Class, R, unsafe extern "C" fn(&Class, Sel $(, $t)*) -> R, $($t),*); ); } @@ -200,7 +219,7 @@ impl ClassBuilder { /// when the method is invoked from Objective-C. pub unsafe fn add_method(&mut self, sel: Sel, func: F) where - T: Message + ?Sized, // TODO: Disallow `Class` + T: Message + ?Sized, F: MethodImplementation, { let encs = F::Args::ENCODINGS; diff --git a/objc2/src/message/mod.rs b/objc2/src/message/mod.rs index a1aebc473..ca01c9457 100644 --- a/objc2/src/message/mod.rs +++ b/objc2/src/message/mod.rs @@ -43,8 +43,6 @@ use self::verify::{verify_message_signature, VerificationError}; /// Types that can be sent Objective-C messages. /// -/// Examples include objects, classes, and blocks. -/// /// Implementing this provides [`MessageReceiver`] implementations for common /// pointer types and references to the type, which allows using them as the /// receiver (first argument) in the [`msg_send!`][`crate::msg_send`] macro. @@ -54,6 +52,9 @@ use self::verify::{verify_message_signature, VerificationError}; /// A pointer to the type must be able to be the receiver of an Objective-C /// message sent with [`objc_msgSend`] or similar. /// +/// The object must also respond to the `retain`, `release` and `autorelease` +/// messages, as that allows it to be used with [`rc::Id`][`Id`]. +/// /// Additionally, the type must implement [`RefEncode`] and adhere to the /// safety requirements therein. /// @@ -65,8 +66,6 @@ unsafe impl Message for ManuallyDrop {} unsafe impl Message for Object {} -unsafe impl Message for Class {} - // TODO: Make this fully private pub(crate) mod private { use super::*; @@ -84,10 +83,15 @@ pub(crate) mod private { impl<'a, T: Message + ?Sized> Sealed for &'a mut Id {} impl Sealed for ManuallyDrop> {} + + impl Sealed for *const Class {} + impl<'a> Sealed for &'a Class {} } /// Types that can directly be used as the receiver of Objective-C messages. /// +/// Examples include objects, classes, and blocks. +/// /// This is a sealed trait (for now) that is automatically implemented for /// pointers to types implementing [`Message`], so that code can be generic /// over the message receiver. @@ -273,6 +277,20 @@ unsafe impl MessageReceiver for ManuallyDrop< } } +unsafe impl MessageReceiver for *const Class { + #[inline] + fn as_raw_receiver(self) -> *mut Object { + self as *mut Class as *mut Object + } +} + +unsafe impl<'a> MessageReceiver for &'a Class { + #[inline] + fn as_raw_receiver(self) -> *mut Object { + self as *const Class as *mut Class as *mut Object + } +} + /// Types that may be used as the arguments of an Objective-C message. /// /// This is implemented for tuples of up to 12 arguments, where each argument diff --git a/tests/ui/fn_ptr_reference_method.stderr b/tests/ui/fn_ptr_reference_method.stderr index ac1f11291..4ab1584f1 100644 --- a/tests/ui/fn_ptr_reference_method.stderr +++ b/tests/ui/fn_ptr_reference_method.stderr @@ -15,7 +15,7 @@ error[E0277]: the trait bound `extern "C" fn(_, _, _): MethodImplementation` is for<'r> extern "C" fn(&'r T, objc2::runtime::Sel, A, B, C, D, E) -> R for<'r> extern "C" fn(&'r T, objc2::runtime::Sel, A, B, C, D, E, F) -> R for<'r> extern "C" fn(&'r T, objc2::runtime::Sel, A, B, C, D, E, F, G) -> R - and 70 others + and 109 others note: required by a bound in `ClassBuilder::add_method` --> $WORKSPACE/objc2/src/declare.rs | @@ -39,7 +39,7 @@ error[E0277]: the trait bound `for<'r> extern "C" fn(_, _, &'r objc2::runtime::O for<'r> extern "C" fn(&'r T, objc2::runtime::Sel, A, B, C, D, E) -> R for<'r> extern "C" fn(&'r T, objc2::runtime::Sel, A, B, C, D, E, F) -> R for<'r> extern "C" fn(&'r T, objc2::runtime::Sel, A, B, C, D, E, F, G) -> R - and 70 others + and 109 others note: required by a bound in `ClassBuilder::add_method` --> $WORKSPACE/objc2/src/declare.rs | diff --git a/tests/ui/msg_send_only_message.stderr b/tests/ui/msg_send_only_message.stderr index 912dcf9bb..cce50d009 100644 --- a/tests/ui/msg_send_only_message.stderr +++ b/tests/ui/msg_send_only_message.stderr @@ -9,8 +9,9 @@ error[E0277]: the trait bound `{integer}: MessageReceiver` is not satisfied &'a T &'a mut Id &'a mut T + &'a objc2::runtime::Class *const T + *const objc2::runtime::Class *mut T - ManuallyDrop> - NonNull + and 2 others = note: this error originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info)