diff --git a/crates/lang/ir/src/ir/attrs.rs b/crates/lang/ir/src/ir/attrs.rs index 27ddec458e7..230a8101298 100644 --- a/crates/lang/ir/src/ir/attrs.rs +++ b/crates/lang/ir/src/ir/attrs.rs @@ -565,6 +565,19 @@ impl InkAttribute { } } +/// Returns an error to notify about non-hex digits at a position. +fn err_non_hex(meta: &syn::Meta, pos: usize) -> syn::Error { + format_err_spanned!(meta, "encountered non-hex digit at position {}", pos) +} + +/// Returns an error to notify about an invalid ink! selector. +fn invalid_selector_err_regex(meta: &syn::Meta) -> syn::Error { + format_err_spanned!( + meta, + "invalid selector - a selector must consist of four bytes in hex (e.g. `selector = \"0xCAFEBABE\"`)" + ) +} + impl TryFrom for AttributeArg { type Error = syn::Error; @@ -577,27 +590,20 @@ impl TryFrom for AttributeArg { if let syn::Lit::Str(lit_str) = &name_value.lit { let regex = Regex::new( r"0x([\da-fA-F]{2})([\da-fA-F]{2})([\da-fA-F]{2})([\da-fA-F]{2})" - ).map_err(|_| { - format_err_spanned!( - meta, - "invalid selector bytes" - ) - })?; + ).map_err(|_| invalid_selector_err_regex(&meta))?; let str = lit_str.value(); - let cap = regex.captures(&str).unwrap(); + let cap = regex + .captures(&str) + .ok_or_else(|| invalid_selector_err_regex(&meta))?; let selector_bytes = [ - u8::from_str_radix(&cap[1], 16).expect( - "encountered non-hex digit at position 0", - ), - u8::from_str_radix(&cap[2], 16).expect( - "encountered non-hex digit at position 1", - ), - u8::from_str_radix(&cap[3], 16).expect( - "encountered non-hex digit at position 2", - ), - u8::from_str_radix(&cap[4], 16).expect( - "encountered non-hex digit at position 3", - ), + u8::from_str_radix(&cap[1], 16) + .map_err(|_| err_non_hex(&meta, 0))?, + u8::from_str_radix(&cap[2], 16) + .map_err(|_| err_non_hex(&meta, 1))?, + u8::from_str_radix(&cap[3], 16) + .map_err(|_| err_non_hex(&meta, 2))?, + u8::from_str_radix(&cap[4], 16) + .map_err(|_| err_non_hex(&meta, 3))?, ]; return Ok(AttributeArg { ast: meta, diff --git a/crates/lang/macro/tests/compile_tests.rs b/crates/lang/macro/tests/compile_tests.rs index 44a9ebec7d6..4804e376cc9 100644 --- a/crates/lang/macro/tests/compile_tests.rs +++ b/crates/lang/macro/tests/compile_tests.rs @@ -44,6 +44,7 @@ fn compile_tests() { t.compile_fail("tests/ui/fail/M-02-message-missing-self-arg.rs"); t.compile_fail("tests/ui/fail/M-03-message-returns-self.rs"); t.compile_fail("tests/ui/fail/M-04-message-returns-non-codec.rs"); + t.compile_fail("tests/ui/fail/M-05-message-invalid-selector.rs"); t.compile_fail("tests/ui/fail/M-10-method-unknown-ink-marker.rs"); t.compile_fail("tests/ui/fail/S-01-missing-storage-struct.rs"); diff --git a/crates/lang/macro/tests/ui/fail/M-05-message-invalid-selector.rs b/crates/lang/macro/tests/ui/fail/M-05-message-invalid-selector.rs new file mode 100644 index 00000000000..83b507eab1b --- /dev/null +++ b/crates/lang/macro/tests/ui/fail/M-05-message-invalid-selector.rs @@ -0,0 +1,19 @@ +use ink_lang as ink; + +#[ink::contract] +mod message_invalid_selector { + #[ink(storage)] + pub struct MessageInvalidSelector {} + + impl MessageInvalidSelector { + #[ink(constructor)] + pub fn constructor() -> Self { + Self {} + } + + #[ink(message, selector = "0x00")] + pub fn invalid_selector(&self) { } + } +} + +fn main() {} diff --git a/crates/lang/macro/tests/ui/fail/M-05-message-invalid-selector.stderr b/crates/lang/macro/tests/ui/fail/M-05-message-invalid-selector.stderr new file mode 100644 index 00000000000..ac4ea433bce --- /dev/null +++ b/crates/lang/macro/tests/ui/fail/M-05-message-invalid-selector.stderr @@ -0,0 +1,5 @@ +error: invalid selector - a selector must consist of four bytes in hex (e.g. `selector = "0xCAFEBABE"`) + --> $DIR/M-05-message-invalid-selector.rs:14:24 + | +14 | #[ink(message, selector = "0x00")] + | ^^^^^^^^^^^^^^^^^