1use super::{
16 Callable,
17 CallableKind,
18 InputsIter,
19 Visibility,
20 ensure_callable_invariants,
21};
22use crate::ir::{
23 self,
24 attrs::SelectorOrWildcard,
25 utils,
26 utils::{
27 extract_cfg_attributes,
28 extract_cfg_syn_attributes,
29 },
30};
31use proc_macro2::{
32 Ident,
33 Span,
34 TokenStream,
35};
36use syn::spanned::Spanned as _;
37
38#[derive(Debug, Copy, Clone, PartialEq, Eq)]
40pub enum Receiver {
41 Ref,
43 RefMut,
45}
46
47impl quote::ToTokens for Receiver {
48 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
49 let receiver = match self {
50 Self::Ref => quote::quote! { &self },
51 Self::RefMut => quote::quote! { &mut self },
52 };
53 tokens.extend(receiver);
54 }
55}
56
57impl Receiver {
58 pub fn is_ref(self) -> bool {
60 matches!(self, Self::Ref)
61 }
62
63 pub fn is_ref_mut(self) -> bool {
65 matches!(self, Self::RefMut)
66 }
67}
68
69#[derive(Debug, PartialEq, Eq)]
101pub struct Message {
102 pub(super) item: syn::ImplItemFn,
104 is_payable: bool,
106 is_default: bool,
108 selector: Option<SelectorOrWildcard>,
115 name: Option<String>,
122}
123
124impl quote::ToTokens for Message {
125 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
128 self.item.to_tokens(tokens)
129 }
130}
131
132impl Message {
133 fn self_ref_receiver(
142 method_item: &syn::ImplItemFn,
143 ) -> Result<&syn::Receiver, syn::Error> {
144 let mut fn_args = method_item.sig.inputs.iter();
145 fn bail(span: Span) -> syn::Error {
146 format_err!(
147 span,
148 "ink! messages must have `&self` or `&mut self` receiver",
149 )
150 }
151 match fn_args.next() {
152 None => Err(bail(method_item.span())),
153 Some(syn::FnArg::Typed(pat_typed)) => Err(bail(pat_typed.span())),
154 Some(syn::FnArg::Receiver(receiver)) => {
155 match receiver.reference {
156 None => Err(bail(receiver.span())),
157 Some(_) => Ok(receiver),
158 }
159 }
160 }
161 }
162
163 fn ensure_not_return_self(method_item: &syn::ImplItemFn) -> Result<(), syn::Error> {
169 match &method_item.sig.output {
170 syn::ReturnType::Default => (),
171 syn::ReturnType::Type(_arrow, ret_type) => {
172 if let syn::Type::Path(type_path) = &**ret_type
173 && type_path.path.is_ident("Self")
174 {
175 return Err(format_err!(
176 ret_type,
177 "ink! messages must not return `Self`"
178 ))
179 }
180 }
181 }
182 Ok(())
183 }
184
185 fn sanitize_attributes(
189 method_item: &syn::ImplItemFn,
190 ) -> Result<(ir::InkAttribute, Vec<syn::Attribute>), syn::Error> {
191 ir::sanitize_attributes(
192 method_item.span(),
193 method_item.attrs.clone(),
194 &ir::AttributeArgKind::Message,
195 |arg| {
196 match arg.kind() {
197 ir::AttributeArg::Message
198 | ir::AttributeArg::Payable
199 | ir::AttributeArg::Default
200 | ir::AttributeArg::Selector(_)
201 | ir::AttributeArg::Name(_) => Ok(()),
202 _ => Err(None),
203 }
204 },
205 )
206 }
207}
208
209impl TryFrom<syn::ImplItemFn> for Message {
210 type Error = syn::Error;
211
212 fn try_from(method_item: syn::ImplItemFn) -> Result<Self, Self::Error> {
213 ensure_callable_invariants(&method_item, CallableKind::Message)?;
214 let self_ref_receiver = Self::self_ref_receiver(&method_item)?;
217 Self::ensure_not_return_self(&method_item)?;
218 let (ink_attrs, other_attrs) = Self::sanitize_attributes(&method_item)?;
219 let is_payable = ink_attrs.is_payable();
220 let is_default = ink_attrs.is_default();
221 let selector = ink_attrs.selector();
222 let name = ink_attrs.name();
223 if is_payable && self_ref_receiver.mutability.is_none() {
225 return Err(format_err!(
226 method_item.span(),
227 "ink! messages with a `payable` attribute argument must have a `&mut self` receiver",
228 ));
229 }
230 #[cfg(ink_abi = "sol")]
231 if selector.is_some() {
232 let selector_span = ink_attrs.args().find_map(|arg| {
233 matches!(arg.kind(), ir::AttributeArg::Selector(_)).then_some(arg.span())
234 });
235 return Err(format_err!(
236 selector_span.unwrap_or_else(|| method_item.span()),
237 "message `selector` attributes are not supported in Solidity ABI compatibility mode",
238 ));
239 }
240 Ok(Self {
241 is_payable,
242 is_default,
243 selector,
244 name,
245 item: syn::ImplItemFn {
246 attrs: other_attrs,
247 ..method_item
248 },
249 })
250 }
251}
252
253impl Callable for Message {
254 fn kind(&self) -> CallableKind {
255 CallableKind::Message
256 }
257
258 fn ident(&self) -> &Ident {
259 &self.item.sig.ident
260 }
261
262 fn user_provided_selector(&self) -> Option<&ir::Selector> {
263 if let Some(SelectorOrWildcard::UserProvided(selector)) = self.selector.as_ref() {
264 return Some(selector)
265 }
266 None
267 }
268
269 fn has_wildcard_selector(&self) -> bool {
270 matches!(self.selector, Some(SelectorOrWildcard::Wildcard))
271 }
272
273 fn has_wildcard_complement_selector(&self) -> bool {
274 self.selector == Some(SelectorOrWildcard::wildcard_complement())
275 }
276
277 fn is_payable(&self) -> bool {
278 self.is_payable
279 }
280
281 fn is_default(&self) -> bool {
282 self.is_default
283 }
284
285 fn visibility(&self) -> Visibility {
286 match &self.item.vis {
287 syn::Visibility::Public(vis_public) => Visibility::Public(*vis_public),
288 syn::Visibility::Inherited => Visibility::Inherited,
289 _ => unreachable!("encountered invalid visibility for ink! message"),
290 }
291 }
292
293 fn inputs(&self) -> InputsIter<'_> {
294 InputsIter::from(self)
295 }
296
297 fn inputs_span(&self) -> Span {
298 self.item.sig.inputs.span()
299 }
300
301 fn statements(&self) -> &[syn::Stmt] {
302 &self.item.block.stmts
303 }
304
305 fn name(&self) -> Option<&str> {
306 self.name.as_deref()
307 }
308}
309
310impl Message {
311 pub fn attrs(&self) -> &[syn::Attribute] {
313 &self.item.attrs
314 }
315
316 pub fn get_cfg_attrs(&self, span: Span) -> Vec<TokenStream> {
318 extract_cfg_attributes(self.attrs(), span)
319 }
320
321 pub fn get_cfg_syn_attrs(&self) -> Vec<syn::Attribute> {
323 extract_cfg_syn_attributes(self.attrs())
324 }
325
326 pub fn receiver(&self) -> Receiver {
328 match self.item.sig.inputs.iter().next() {
329 Some(syn::FnArg::Receiver(receiver)) => {
330 debug_assert!(receiver.reference.is_some());
331 if receiver.mutability.is_some() {
332 Receiver::RefMut
333 } else {
334 Receiver::Ref
335 }
336 }
337 _ => unreachable!("encountered invalid receiver argument for ink! message"),
338 }
339 }
340
341 pub fn output(&self) -> Option<&syn::Type> {
343 match &self.item.sig.output {
344 syn::ReturnType::Default => None,
345 syn::ReturnType::Type(_, return_type) => Some(return_type),
346 }
347 }
348
349 pub fn wrapped_output(&self) -> syn::Type {
354 let return_type = self
355 .output()
356 .map(quote::ToTokens::to_token_stream)
357 .unwrap_or_else(|| quote::quote! { () });
358
359 syn::parse_quote! {
360 ::ink::MessageResult<#return_type>
361 }
362 }
363
364 pub fn local_id(&self) -> u32 {
373 utils::local_message_id(self.ident())
374 }
375
376 pub fn try_ident(&self) -> Ident {
378 quote::format_ident!("try_{}", self.ident())
379 }
380
381 pub fn name(&self) -> Option<&str> {
383 self.name.as_deref()
384 }
385}
386
387#[cfg(test)]
388mod tests {
389 use super::*;
390
391 #[test]
392 fn output_works() {
393 let test_inputs: Vec<(Option<syn::Type>, syn::ImplItemFn)> = vec![
394 (
395 None,
397 syn::parse_quote! {
398 #[ink(message)]
399 fn my_message(&self) {}
400 },
401 ),
402 (
403 Some(syn::parse_quote! { i32 }),
405 syn::parse_quote! {
406 #[ink(message)]
407 fn my_message(&self) -> i32 {}
408 },
409 ),
410 (
411 Some(syn::parse_quote! { (i32, u64, bool) }),
413 syn::parse_quote! {
414 #[ink(message)]
415 fn my_message(&self) -> (i32, u64, bool) {}
416 },
417 ),
418 ];
419 for (expected_output, item_method) in test_inputs {
420 let actual_output = <ir::Message as TryFrom<_>>::try_from(item_method)
421 .unwrap()
422 .output()
423 .cloned();
424 assert_eq!(actual_output, expected_output);
425 }
426 }
427
428 #[test]
429 fn inputs_works() {
430 macro_rules! expected_input {
431 ( mut $name:ident: $ty:ty ) => {{
432 syn::parse_quote! {
433 mut $name: $ty
434 }
435 }};
436 ( $name:ident: $ty:ty ) => {{
437 syn::parse_quote! {
438 $name: $ty
439 }
440 }};
441 }
442 macro_rules! expected_inputs {
443 ( $( $($ts:ident)+: $ty:ty ),* ) => {{
444 vec![
445 $(
446 expected_input!($($ts)+: $ty)
447 ),*
448 ]
449 }};
450 }
451 let test_inputs: Vec<(Vec<syn::FnArg>, syn::ImplItemFn)> = vec![
452 (
453 expected_inputs!(),
455 syn::parse_quote! {
456 #[ink(message)]
457 fn my_message(&self) {}
458 },
459 ),
460 (
461 expected_inputs!(a: i32),
463 syn::parse_quote! {
464 #[ink(message)]
465 fn my_message(&self, a: i32) {}
466 },
467 ),
468 (
469 expected_inputs!(mut a: i32),
471 syn::parse_quote! {
472 #[ink(message)]
473 fn my_message(&self, mut a: i32) {}
474 },
475 ),
476 (
477 expected_inputs!(a: i32, b: u64, mut c: [u8; 32]),
479 syn::parse_quote! {
480 #[ink(message)]
481 fn my_message(&self, a: i32, b: u64, mut c: [u8; 32]) {}
482 },
483 ),
484 ];
485 for (expected_inputs, item_method) in test_inputs {
486 let actual_inputs = <ir::Message as TryFrom<_>>::try_from(item_method)
487 .unwrap()
488 .inputs()
489 .cloned()
490 .map(syn::FnArg::Typed)
491 .collect::<Vec<_>>();
492 assert_eq!(actual_inputs, expected_inputs);
493 }
494 }
495
496 #[test]
497 fn is_payable_works() {
498 let test_inputs: Vec<(bool, syn::ImplItemFn)> = vec![
499 (
501 false,
502 syn::parse_quote! {
503 #[ink(message)]
504 fn my_message(&self) {}
505 },
506 ),
507 (
509 true,
510 syn::parse_quote! {
511 #[ink(message, payable)]
512 pub fn my_message(&mut self) {}
513 },
514 ),
515 (
517 true,
518 syn::parse_quote! {
519 #[ink(message)]
520 #[ink(payable)]
521 pub fn my_message(&mut self) {}
522 },
523 ),
524 (
526 true,
527 syn::parse_quote! {
528 #[ink(message)]
529 #[ink(selector = 0xDEADBEEF, payable)]
530 pub fn my_message(&mut self) {}
531 },
532 ),
533 ];
534 for (expect_payable, item_method) in test_inputs {
535 let is_payable = <ir::Message as TryFrom<_>>::try_from(item_method)
536 .unwrap()
537 .is_payable();
538 assert_eq!(is_payable, expect_payable);
539 }
540 }
541
542 #[test]
543 fn is_default_works() {
544 let test_inputs: Vec<(bool, syn::ImplItemFn)> = vec![
545 (
547 false,
548 syn::parse_quote! {
549 #[ink(message)]
550 fn my_message(&self) {}
551 },
552 ),
553 (
555 true,
556 syn::parse_quote! {
557 #[ink(message, payable, default)]
558 pub fn my_message(&mut self) {}
559 },
560 ),
561 ];
562 for (expect_default, item_method) in test_inputs {
563 let is_default = <ir::Message as TryFrom<_>>::try_from(item_method)
564 .unwrap()
565 .is_default();
566 assert_eq!(is_default, expect_default);
567 }
568 }
569
570 #[test]
571 fn name_override_works() {
572 let test_inputs: Vec<(Option<&str>, syn::ImplItemFn)> = vec![
573 (
575 None,
576 syn::parse_quote! {
577 #[ink(message)]
578 fn my_message(&self) {}
579 },
580 ),
581 (
583 Some("myMessage"),
584 syn::parse_quote! {
585 #[ink(message, name = "myMessage")]
586 pub fn my_message(&mut self) {}
587 },
588 ),
589 ];
590 for (expected_name, item_method) in test_inputs {
591 let message = <ir::Message as TryFrom<_>>::try_from(item_method).unwrap();
592 assert_eq!(message.name(), expected_name);
593 }
594 }
595
596 #[test]
597 fn receiver_works() {
598 let test_inputs: Vec<(Receiver, syn::ImplItemFn)> = vec![
599 (
600 Receiver::Ref,
601 syn::parse_quote! {
602 #[ink(message)]
603 fn my_message(&self) {}
604 },
605 ),
606 (
607 Receiver::RefMut,
608 syn::parse_quote! {
609 #[ink(message, payable)]
610 fn my_message(&mut self) {}
611 },
612 ),
613 ];
614 for (expected_receiver, item_method) in test_inputs {
615 let actual_receiver = <ir::Message as TryFrom<_>>::try_from(item_method)
616 .unwrap()
617 .receiver();
618 assert_eq!(actual_receiver, expected_receiver);
619 }
620 }
621
622 #[test]
623 fn visibility_works() {
624 let test_inputs: Vec<(bool, syn::ImplItemFn)> = vec![
625 (
627 false,
628 syn::parse_quote! {
629 #[ink(message)]
630 fn my_message(&self) {}
631 },
632 ),
633 (
635 true,
636 syn::parse_quote! {
637 #[ink(message)]
638 pub fn my_message(&self) {}
639 },
640 ),
641 (
643 false,
644 syn::parse_quote! {
645 #[ink(message)]
646 fn my_message(&mut self) {}
647 },
648 ),
649 (
651 true,
652 syn::parse_quote! {
653 #[ink(message)]
654 pub fn my_message(&mut self) {}
655 },
656 ),
657 ];
658 for (is_pub, item_method) in test_inputs {
659 let visibility = <ir::Message as TryFrom<_>>::try_from(item_method)
660 .unwrap()
661 .visibility();
662 assert_eq!(visibility.is_pub(), is_pub);
663 assert_eq!(visibility.is_inherited(), !is_pub);
664 }
665 }
666
667 #[test]
668 fn try_from_works() {
669 let item_methods: Vec<syn::ImplItemFn> = vec![
670 syn::parse_quote! {
672 #[ink(message)]
673 fn my_message(&self) {}
674 },
675 syn::parse_quote! {
677 #[ink(message)]
678 pub fn my_message(&self) {}
679 },
680 syn::parse_quote! {
682 #[ink(message)]
683 fn my_message(&mut self) {}
684 },
685 syn::parse_quote! {
687 #[ink(message)]
688 pub fn my_message(&mut self) {}
689 },
690 syn::parse_quote! {
692 #[ink(message, payable)]
693 fn my_message(&mut self) {}
694 },
695 syn::parse_quote! {
697 #[ink(message, payable)]
698 fn my_message(&mut self) {}
699 },
700 syn::parse_quote! {
702 #[ink(message)]
703 fn my_message(&self, input1: i32, input2: i64, input3: u32, input4: u64) -> bool {}
704 },
705 syn::parse_quote! {
707 #[ink(message)]
708 fn my_message(&mut self, input1: i32, input2: i64, input3: u32, input4: u64) -> bool {}
709 },
710 ];
711 for item_method in item_methods {
712 assert!(<ir::Message as TryFrom<_>>::try_from(item_method).is_ok());
713 }
714 }
715
716 fn assert_try_from_fails(item_method: syn::ImplItemFn, expected_err: &str) {
717 assert_eq!(
718 <ir::Message as TryFrom<_>>::try_from(item_method)
719 .map_err(|err| err.to_string()),
720 Err(expected_err.to_string()),
721 );
722 }
723
724 #[test]
725 fn try_from_generics_fails() {
726 let item_methods: Vec<syn::ImplItemFn> = vec![
727 syn::parse_quote! {
728 #[ink(message)]
729 fn my_message<T>(&self) {}
730 },
731 syn::parse_quote! {
732 #[ink(message)]
733 pub fn my_message<T>(&self) {}
734 },
735 syn::parse_quote! {
736 #[ink(message)]
737 fn my_message<T>(&mut self) {}
738 },
739 syn::parse_quote! {
740 #[ink(message)]
741 pub fn my_message<T>(&mut self) {}
742 },
743 ];
744 for item_method in item_methods {
745 assert_try_from_fails(item_method, "ink! messages must not be generic")
746 }
747 }
748
749 #[test]
750 fn try_from_receiver_fails() {
751 let item_methods: Vec<syn::ImplItemFn> = vec![
752 syn::parse_quote! {
753 #[ink(message)]
754 fn my_message() {}
755 },
756 syn::parse_quote! {
757 #[ink(message)]
758 fn my_message(self) {}
759 },
760 syn::parse_quote! {
761 #[ink(message)]
762 pub fn my_message(mut self) {}
763 },
764 syn::parse_quote! {
765 #[ink(message)]
766 fn my_message(this: &Self) {}
767 },
768 syn::parse_quote! {
769 #[ink(message)]
770 pub fn my_message(this: &mut Self) {}
771 },
772 ];
773 for item_method in item_methods {
774 assert_try_from_fails(
775 item_method,
776 "ink! messages must have `&self` or `&mut self` receiver",
777 )
778 }
779 }
780
781 #[test]
782 fn try_from_const_fails() {
783 let item_methods: Vec<syn::ImplItemFn> = vec![
784 syn::parse_quote! {
786 #[ink(message)]
787 const fn my_message(&self) {}
788 },
789 syn::parse_quote! {
791 #[ink(message)]
792 const fn my_message(&mut self) {}
793 },
794 ];
795 for item_method in item_methods {
796 assert_try_from_fails(item_method, "ink! messages must not be const")
797 }
798 }
799
800 #[test]
801 fn try_from_async_fails() {
802 let item_methods: Vec<syn::ImplItemFn> = vec![
803 syn::parse_quote! {
805 #[ink(message)]
806 async fn my_message(&self) {}
807 },
808 syn::parse_quote! {
810 #[ink(message)]
811 async fn my_message(&mut self) {}
812 },
813 ];
814 for item_method in item_methods {
815 assert_try_from_fails(item_method, "ink! messages must not be async")
816 }
817 }
818
819 #[test]
820 fn try_from_unsafe_fails() {
821 let item_methods: Vec<syn::ImplItemFn> = vec![
822 syn::parse_quote! {
824 #[ink(message)]
825 unsafe fn my_message(&self) {}
826 },
827 syn::parse_quote! {
829 #[ink(message)]
830 unsafe fn my_message(&mut self) {}
831 },
832 ];
833 for item_method in item_methods {
834 assert_try_from_fails(item_method, "ink! messages must not be unsafe")
835 }
836 }
837
838 #[test]
839 fn try_from_explicit_abi_fails() {
840 let item_methods: Vec<syn::ImplItemFn> = vec![
841 syn::parse_quote! {
843 #[ink(message)]
844 extern "C" fn my_message(&self) {}
845 },
846 syn::parse_quote! {
848 #[ink(message)]
849 extern "C" fn my_message(&mut self) {}
850 },
851 ];
852 for item_method in item_methods {
853 assert_try_from_fails(item_method, "ink! messages must not have explicit ABI")
854 }
855 }
856
857 #[test]
858 fn try_from_variadic_fails() {
859 let item_methods: Vec<syn::ImplItemFn> = vec![
860 syn::parse_quote! {
862 #[ink(message)]
863 fn my_message(&self, ...) {}
864 },
865 syn::parse_quote! {
867 #[ink(message)]
868 fn my_message(&mut self, ...) {}
869 },
870 ];
871 for item_method in item_methods {
872 assert_try_from_fails(item_method, "ink! messages must not be variadic")
873 }
874 }
875
876 #[test]
877 fn try_from_visibility_fails() {
878 let item_methods: Vec<syn::ImplItemFn> = vec![
879 syn::parse_quote! {
881 #[ink(message)]
882 pub(crate) fn my_message(&self) {}
883 },
884 syn::parse_quote! {
886 #[ink(message)]
887 pub(crate) fn my_message(&mut self) {}
888 },
889 syn::parse_quote! {
891 #[ink(message)]
892 pub(in my::path) fn my_message(&self) {}
893 },
894 syn::parse_quote! {
896 #[ink(message)]
897 pub(in my::path) fn my_message(&mut self) {}
898 },
899 ];
900 for item_method in item_methods {
901 assert_try_from_fails(
902 item_method,
903 "ink! messages must have public or inherited visibility",
904 )
905 }
906 }
907
908 #[test]
909 fn conflicting_attributes_fails() {
910 let item_methods: Vec<syn::ImplItemFn> = vec![
911 syn::parse_quote! {
913 #[ink(message, storage)]
914 fn my_message(&self) {}
915 },
916 syn::parse_quote! {
918 #[ink(message, namespace = "my_namespace")]
919 fn my_message(&self) {}
920 },
921 syn::parse_quote! {
923 #[ink(message)]
924 #[ink(event)]
925 fn my_message(&self) {}
926 },
927 ];
928 for item_method in item_methods {
929 assert_try_from_fails(
930 item_method,
931 "encountered conflicting ink! attribute argument",
932 )
933 }
934 }
935}