diff --git a/objc2/src/macros/extern_methods.rs b/objc2/src/macros/extern_methods.rs index 85b387b7a..22073d3e6 100644 --- a/objc2/src/macros/extern_methods.rs +++ b/objc2/src/macros/extern_methods.rs @@ -329,7 +329,7 @@ macro_rules! __inner_extern_methods { $crate::msg_send; $self; ($($sel)*); - ($($arg),*); + ($($arg,)*); ) }; { @@ -346,198 +346,53 @@ macro_rules! __inner_extern_methods { $crate::msg_send; Self::class(); ($($sel)*); - ($($arg),*); + ($($arg,)*); ) }; } /// Zip selector and arguments, and forward to macro. -/// -/// TODO: Investigate if there's a better way of doing this. #[doc(hidden)] #[macro_export] macro_rules! __collect_msg_send { + // Selector with no arguments ( $macro:path; $obj:expr; - ($s:ident); - (); - ) => {{ - $macro![$obj, $s] - }}; - ( - $macro:path; - $obj:expr; - ($s1:ident:); - ($a1:expr); + ($sel:ident); + ($(,)?); ) => {{ - $macro![$obj, $s1: $a1] - }}; - ( - $macro:path; - $obj:expr; - ($s1:ident: $s2:ident:); - ($a1:expr, $a2:expr); - ) => {{ - $macro![$obj, $s1: $a1, $s2: $a2] - }}; - ( - $macro:path; - $obj:expr; - ($s1:ident: $s2:ident: $s3:ident:); - ($a1:expr, $a2:expr, $a3:expr); - ) => {{ - $macro![$obj, $s1: $a1, $s2: $a2, $s3: $a3] - }}; - ( - $macro:path; - $obj:expr; - ($s1:ident: $s2:ident: $s3:ident: $s4:ident:); - ($a1:expr, $a2:expr, $a3:expr, $a4:expr); - ) => {{ - $macro![$obj, $s1: $a1, $s2: $a2, $s3: $a3, $s4: $a4] - }}; - ( - $macro:path; - $obj:expr; - ($s1:ident: $s2:ident: $s3:ident: $s4:ident: $s5:ident:); - ($a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr); - ) => {{ - $macro![$obj, $s1: $a1, $s2: $a2, $s3: $a3, $s4: $a4, $s5: $a5] - }}; - ( - $macro:path; - $obj:expr; - ($s1:ident: $s2:ident: $s3:ident: $s4:ident: $s5:ident: $s6:ident:); - ($a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr, $a6:expr); - ) => {{ - $macro![ - $obj, - $s1: $a1, - $s2: $a2, - $s3: $a3, - $s4: $a4, - $s5: $a5, - $s6: $a6 - ] - }}; - ( - $macro:path; - $obj:expr; - ($s1:ident: $s2:ident: $s3:ident: $s4:ident: $s5:ident: $s6:ident: $s7:ident:); - ($a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr, $a6:expr, $a7:expr); - ) => {{ - $macro![ - $obj, - $s1: $a1, - $s2: $a2, - $s3: $a3, - $s4: $a4, - $s5: $a5, - $s6: $a6, - $s7: $a7 - ] - }}; - ( - $macro:path; - $obj:expr; - ($s1:ident: $s2:ident: $s3:ident: $s4:ident: $s5:ident: $s6:ident: $s7:ident: $s8:ident:); - ($a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr, $a6:expr, $a7:expr, $a8:expr); - ) => {{ - $macro![ - $obj, - $s1: $a1, - $s2: $a2, - $s3: $a3, - $s4: $a4, - $s5: $a5, - $s6: $a6, - $s7: $a7, - $s8: $a8 - ] - }}; - ( - $macro:path; - $obj:expr; - ($s1:ident: $s2:ident: $s3:ident: $s4:ident: $s5:ident: $s6:ident: $s7:ident: $s8:ident: $s9:ident:); - ($a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr, $a6:expr, $a7:expr, $a8:expr, $a9:expr); - ) => {{ - $macro![ - $obj, - $s1: $a1, - $s2: $a2, - $s3: $a3, - $s4: $a4, - $s5: $a5, - $s6: $a6, - $s7: $a7, - $s8: $a8, - $s9: $a9 - ] - }}; - ( - $macro:path; - $obj:expr; - ($s1:ident: $s2:ident: $s3:ident: $s4:ident: $s5:ident: $s6:ident: $s7:ident: $s8:ident: $s9:ident: $s10:ident:); - ($a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr, $a6:expr, $a7:expr, $a8:expr, $a9:expr, $a10:expr); - ) => {{ - $macro![ - $obj, - $s1: $a1, - $s2: $a2, - $s3: $a3, - $s4: $a4, - $s5: $a5, - $s6: $a6, - $s7: $a7, - $s8: $a8, - $s9: $a9, - $s10: $a10 - ] + $macro![$obj, $sel] }}; + + // Base case ( $macro:path; $obj:expr; - ($s1:ident: $s2:ident: $s3:ident: $s4:ident: $s5:ident: $s6:ident: $s7:ident: $s8:ident: $s9:ident: $s10:ident: $s11:ident:); - ($a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr, $a6:expr, $a7:expr, $a8:expr, $a9:expr, $a10:expr, $a11:expr); + (); + ($(,)?); + $($output:tt)+ ) => {{ - $macro![ - $obj, - $s1: $a1, - $s2: $a2, - $s3: $a3, - $s4: $a4, - $s5: $a5, - $s6: $a6, - $s7: $a7, - $s8: $a8, - $s9: $a9, - $s10: $a10, - $s11: $a11 - ] + $macro![$obj, $($output)+] }}; + // tt-munch each argument ( $macro:path; $obj:expr; - ($s1:ident: $s2:ident: $s3:ident: $s4:ident: $s5:ident: $s6:ident: $s7:ident: $s8:ident: $s9:ident: $s10:ident: $s11:ident: $s12:ident:); - ($a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr, $a6:expr, $a7:expr, $a8:expr, $a9:expr, $a10:expr, $a11:expr, $a12:expr); + ($sel:ident : $($sel_rest:tt)*); + ($arg:ident , $($args_rest:tt)*); + $($output:tt)* ) => {{ - $macro![ - $obj, - $s1: $a1, - $s2: $a2, - $s3: $a3, - $s4: $a4, - $s5: $a5, - $s6: $a6, - $s7: $a7, - $s8: $a8, - $s9: $a9, - $s10: $a10, - $s11: $a11, - $s12: $a12 - ] + $crate::__collect_msg_send!( + $macro; + $obj; + ($($sel_rest)*); + ($($args_rest)*); + $($output)* $sel: $arg, + ) }}; + + // If couldn't zip selector and arguments, show useful error message ($($_any:tt)*) => {{ compile_error!("Number of arguments in function and selector did not match!") }}; diff --git a/test-ui/ui/extern_methods_wrong_arguments.rs b/test-ui/ui/extern_methods_wrong_arguments.rs new file mode 100644 index 000000000..8eb5f408d --- /dev/null +++ b/test-ui/ui/extern_methods_wrong_arguments.rs @@ -0,0 +1,47 @@ +use objc2::{extern_class, extern_methods, ClassType}; +use objc2::foundation::NSObject; + +extern_class!( + pub struct MyObject; + + unsafe impl ClassType for MyObject { + type Superclass = NSObject; + } +); + +extern_methods!( + unsafe impl MyObject { + #[sel(a:)] + fn a(); + } +); + +extern_methods!( + unsafe impl MyObject { + #[sel(b)] + fn b(arg: i32); + } +); + +extern_methods!( + unsafe impl MyObject { + #[sel(c:d:e:)] + fn c(arg1: i32, arg2: u32); + } +); + +extern_methods!( + unsafe impl MyObject { + #[sel(x:)] + fn x(&self); + } +); + +extern_methods!( + unsafe impl MyObject { + #[sel(y)] + fn y(&self, arg: i32); + } +); + +fn main() {} diff --git a/test-ui/ui/extern_methods_wrong_arguments.stderr b/test-ui/ui/extern_methods_wrong_arguments.stderr new file mode 100644 index 000000000..678d64852 --- /dev/null +++ b/test-ui/ui/extern_methods_wrong_arguments.stderr @@ -0,0 +1,64 @@ +error: Number of arguments in function and selector did not match! + --> ui/extern_methods_wrong_arguments.rs + | + | / extern_methods!( + | | unsafe impl MyObject { + | | #[sel(a:)] + | | fn a(); + | | } + | | ); + | |_^ + | + = note: this error originates in the macro `$crate::__collect_msg_send` which comes from the expansion of the macro `extern_methods` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: Number of arguments in function and selector did not match! + --> ui/extern_methods_wrong_arguments.rs + | + | / extern_methods!( + | | unsafe impl MyObject { + | | #[sel(b)] + | | fn b(arg: i32); + | | } + | | ); + | |_^ + | + = note: this error originates in the macro `$crate::__collect_msg_send` which comes from the expansion of the macro `extern_methods` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: Number of arguments in function and selector did not match! + --> ui/extern_methods_wrong_arguments.rs + | + | / extern_methods!( + | | unsafe impl MyObject { + | | #[sel(c:d:e:)] + | | fn c(arg1: i32, arg2: u32); + | | } + | | ); + | |_^ + | + = note: this error originates in the macro `$crate::__collect_msg_send` which comes from the expansion of the macro `extern_methods` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: Number of arguments in function and selector did not match! + --> ui/extern_methods_wrong_arguments.rs + | + | / extern_methods!( + | | unsafe impl MyObject { + | | #[sel(x:)] + | | fn x(&self); + | | } + | | ); + | |_^ + | + = note: this error originates in the macro `$crate::__collect_msg_send` which comes from the expansion of the macro `extern_methods` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: Number of arguments in function and selector did not match! + --> ui/extern_methods_wrong_arguments.rs + | + | / extern_methods!( + | | unsafe impl MyObject { + | | #[sel(y)] + | | fn y(&self, arg: i32); + | | } + | | ); + | |_^ + | + = note: this error originates in the macro `$crate::__collect_msg_send` which comes from the expansion of the macro `extern_methods` (in Nightly builds, run with -Z macro-backtrace for more info)