Browse Source

Use annotations for selectors (#1095)

Use new annotations:

	@selector([1,1,2,5])
	function foo() {}

Rather than:

	function foo() selector=hex"01010205" {}

This removes the old syntax completely.

Signed-off-by: Sean Young <sean@mess.org>
Co-authored-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
Co-authored-by: Lucas Steuernagel <38472950+LucasSte@users.noreply.github.com>
Sean Young 2 năm trước cách đây
mục cha
commit
bd65c96b44
31 tập tin đã thay đổi với 593 bổ sung368 xóa
  1. 27 13
      CHANGELOG.md
  2. 8 1
      docs/examples/substrate/function_selector_override.sol
  3. 2 2
      docs/language/functions.rst
  4. 2 1
      integration/substrate/inkee.sol
  5. 0 1
      solang-parser/src/pt.rs
  6. 0 3
      solang-parser/src/solidity.lalrpop
  7. 4 4
      solang-parser/src/test.rs
  8. 7 10
      src/bin/idl/mod.rs
  9. 2 2
      src/sema/ast.rs
  10. 23 19
      src/sema/contracts.rs
  11. 1 1
      src/sema/dotgraphviz.rs
  12. 1 1
      src/sema/eval.rs
  13. 2 2
      src/sema/expression.rs
  14. 136 3
      src/sema/function_annotation.rs
  15. 6 111
      src/sema/functions.rs
  16. 2 2
      src/sema/statements.rs
  17. 15 15
      tests/contract_testcases/evm/selector_override.dot
  18. 12 6
      tests/contract_testcases/evm/selector_override.sol
  19. 1 1
      tests/contract_testcases/solana/annotations_bad.dot
  20. 45 33
      tests/contract_testcases/solana/functions/selector_override.dot
  21. 24 6
      tests/contract_testcases/solana/functions/selector_override.sol
  22. 51 67
      tests/contract_testcases/solana/functions/selectors-must-be-different.dot
  23. 16 8
      tests/contract_testcases/solana/functions/selectors-must-be-different.sol
  24. 58 0
      tests/contract_testcases/solana/selector_override.dot
  25. 80 0
      tests/contract_testcases/solana/selectors-must-be-different.dot
  26. 19 17
      tests/contract_testcases/substrate/selector_override.dot
  27. 12 6
      tests/contract_testcases/substrate/selector_override.sol
  28. 24 24
      tests/contract_testcases/substrate/selector_override_inherited.dot
  29. 7 6
      tests/contract_testcases/substrate/selector_override_inherited.sol
  30. 2 1
      tests/doc_examples.rs
  31. 4 2
      tests/substrate_tests/functions.rs

+ 27 - 13
CHANGELOG.md

@@ -2,13 +2,27 @@
 All notable changes to [Solang](https://github.com/hyperledger/solang/)
 will be documented here.
 
+## Unreleased
+
+### Changed
+- Overriding the function selector value is now done using the `@selector([1, 2, 3, 4])`
+  syntax, and the old syntax `selector=hex"12345678"` has been removed.
+  [seanyoung](https://github.com/seanyoung)
+
 ## v0.2.0.0 Berlin
-We are happy to release solang `v0.2.0` codenamed `Berlin` today. Aside from containing many small fixes and improvements, this release marks a milestone towards maturing our Substrate compilation target: any regressions building up since `ink!` v3.0 are fixed, most notably the metadata format (shoutout and many thanks to external contributor [extraymond](https://github.com/extraymond)) and event topics. Furthermore, we are leaving `ink!` version 3 behind us, in favor of introducing compatibility with the recent `ink!` 4 beta release and the latest pallet contract `v0.22.1`.
+We are happy to release solang `v0.2.0` codenamed `Berlin` today. Aside from
+containing many small fixes and improvements, this release marks a milestone
+towards maturing our Substrate compilation target: any regressions building up
+since `ink!` v3.0 are fixed, most notably the metadata format (shoutout and many
+thanks to external contributor [extraymond](https://github.com/extraymond)) and
+event topics. Furthermore, we are leaving `ink!` version 3 behind us, in favor
+of introducing compatibility with the recent `ink!` 4 beta release and the latest
+substrate contracts node `v0.22.1`.
 
 ### Added
 - **Solana / breaking:** The try-catch construct is no longer permitted on Solana, as it
-   never worked. Any CPI error will abort the transaction.
-   [seanyoung](https://github.com/seanyoung)
+  never worked. Any CPI error will abort the transaction.
+  [seanyoung](https://github.com/seanyoung)
 - **Solana:** Introduce new sub-command `solang idl` which can be used for generating
   a Solidity interface file from an Anchor IDL file. This can be used for calling
   Anchor Contracts on Solana. [seanyoung](https://github.com/seanyoung)
@@ -24,27 +38,27 @@ We are happy to release solang `v0.2.0` codenamed `Berlin` today. Aside from con
   [xermicus](https://github.com/xermicus)
 
 ### Changed
- - The Solana target now uses Borsh encoding rather than eth abi
-   encoding. This is aimed at making Solang contracts Anchor compatible.
-   [LucasSte](https://github.com/LucasSte)
+- The Solana target now uses Borsh encoding rather than eth abi
+  encoding. This is aimed at making Solang contracts Anchor compatible.
+  [LucasSte](https://github.com/LucasSte)
 - **Substrate / breaking:** Supported node version is now pallet contracts `v0.22.1`.
   [xermicus](https://github.com/xermicus)
 - **Substrate / breaking:** Remove the deprecated `random` builtin.
   [xermicus](https://github.com/xermicus)
 
 ### Fixed
- - Whenever possible, the parser does not give up after the first error.
-   [salaheldinsoliman](https://github.com/salaheldinsoliman)
- - Constant expressions are checked for overflow.
-   [salaheldinsoliman](https://github.com/salaheldinsoliman)
- - AddMod and MulMod were broken. This is now fixed.
-   [LucasSte](https://github.com/LucasSte)
+- Whenever possible, the parser does not give up after the first error.
+  [salaheldinsoliman](https://github.com/salaheldinsoliman)
+- Constant expressions are checked for overflow.
+  [salaheldinsoliman](https://github.com/salaheldinsoliman)
+- AddMod and MulMod were broken. This is now fixed.
+  [LucasSte](https://github.com/LucasSte)
 - **Substrate / breaking:** Solang is now compatible with `ink!` version 4 (beta).
   [xermicus](https://github.com/xermicus)
 - **Substrate:** Switched ABI generation to use official `ink!` crates, which fixes all
   remaining metadata regressions.
   [extraymond](https://github.com/extraymond) and [xermicus](https://github.com/xermicus)
-- **Substrate:** Allow constructors to have a name, so that multiple constructors are 
+- **Substrate:** Allow constructors to have a name, so that multiple constructors are
   supported, like in `ink!`.
   [xermicus](https://github.com/xermicus)
 - All provided examples as well as most of the Solidity code snippets in our

+ 8 - 1
docs/examples/substrate/function_selector_override.sol

@@ -1,5 +1,12 @@
 contract foo {
-    function get_foo() selector=hex"01020304" public returns (int) {
+    // The selector attribute can be an array of values (bytes)
+    @selector([1, 2, 3, 4])
+    function get_foo() pure public returns (int) {
         return 102;
     }
+
+    @selector([0x05, 0x06, 0x07, 0x08])
+    function get_bar() pure public returns (int) {
+        return 105;
+    }
 }

+ 2 - 2
docs/language/functions.rst

@@ -159,8 +159,8 @@ what the runtime program uses to determine what function was called. On Substrat
 function selector is generated using a deterministic hash value of the function
 name and the arguments types. On Solana, the selector is known as discriminator.
 
-The selector value can be overriden with the ``selector=hex"deadbea1"`` syntax,
-for example:
+The selector value can be overriden with the annotation
+``@selector([0xde, 0xad, 0xbe, 0xa1])``.
 
 .. include:: ../examples/substrate/function_selector_override.sol
   :code: solidity

+ 2 - 1
integration/substrate/inkee.sol

@@ -1,5 +1,6 @@
 contract Inkee {
-    function echo(uint32 v) selector=hex"01020304" public pure returns (uint32) {
+    @selector([1, 2, 3, 4])
+    function echo(uint32 v) public pure returns (uint32) {
         return v;
     }
 }

+ 0 - 1
solang-parser/src/pt.rs

@@ -704,7 +704,6 @@ pub enum FunctionAttribute {
     Immutable(Loc),
     Override(Loc, Vec<IdentifierPath>),
     BaseOrModifier(Loc, Base),
-    NameValue(Loc, Identifier, Expression),
     Error(Loc),
 }
 

+ 0 - 3
solang-parser/src/solidity.lalrpop

@@ -579,9 +579,6 @@ FunctionAttribute: FunctionAttribute = {
         FunctionAttribute::Override(Loc::File(file_no, l, r), list)
     },
     <l:@L> <base:Base> <r:@R> => FunctionAttribute::BaseOrModifier(Loc::File(file_no, l, r), base),
-    <l:@L> <name:SolIdentifier> "=" <value:LiteralExpression> <r:@R> => {
-        FunctionAttribute::NameValue(Loc::File(file_no, l, r), name, value)
-    },
     <l:@L> <false_token:!> <r:@R> => {
         parser_errors.push(false_token);
         FunctionAttribute::Error(Loc::File(file_no, l ,r))

+ 4 - 4
solang-parser/src/test.rs

@@ -48,19 +48,19 @@ contract 9c {
                 Diagnostic { loc: File(0, 62, 65), level: Error, ty: ParserError, message: r#"unrecognised token 'for', expected ";", "=""#.to_string(), notes: vec![] },
                 Diagnostic { loc: File(0, 78, 79), level: Error, ty: ParserError, message: r#"unrecognised token '9', expected "case", "default", "error", "leave", "revert", "switch", identifier"#.to_string(), notes: vec![] },
                 Diagnostic { loc: File(0, 95, 96), level: Error, ty: ParserError, message: r#"unrecognised token '0', expected "!=", "%", "%=", "&", "&&", "&=", "(", ")", "*", "**", "*=", "+", "++", "+=", ",", "-", "--", "-=", ".", "/", "/=", ":", ";", "<", "<<", "<<=", "<=", "=", "==", "=>", ">", ">=", ">>", ">>=", "?", "[", "]", "^", "^=", "calldata", "case", "constant", "days", "default", "error", "ether", "external", "gwei", "hours", "immutable", "indexed", "internal", "leave", "memory", "minutes", "override", "private", "public", "revert", "seconds", "storage", "switch", "weeks", "wei", "{", "|", "|=", "||", "}", identifier"#.to_string(), notes: vec![] },
-                Diagnostic { loc: File(0, 116, 123), level: Error, ty: ParserError, message: r#"unrecognised token 'uint256', expected "!=", "%", "%=", "&", "&&", "&=", "(", ")", "*", "**", "*=", "+", "++", "+=", ",", "-", "--", "-=", ".", "/", "/=", ":", ";", "<", "<<", "<<=", "<=", "=", "==", "=>", ">", ">=", ">>", ">>=", "?", "[", "]", "^", "^=", "calldata", "case", "constant", "days", "default", "error", "ether", "external", "gwei", "hours", "immutable", "indexed", "internal", "leave", "memory", "minutes", "override", "payable", "private", "public", "pure", "return", "returns", "revert", "seconds", "storage", "switch", "view", "virtual", "weeks", "wei", "{", "|", "|=", "||", "}", identifier"#.to_string(), notes: vec![] },
+                Diagnostic { loc: File(0, 116, 123), level: Error, ty: ParserError, message: r#"unrecognised token 'uint256', expected "!=", "%", "%=", "&", "&&", "&=", "(", ")", "*", "**", "*=", "+", "++", "+=", ",", "-", "--", "-=", ".", "/", "/=", ":", ";", "<", "<<", "<<=", "<=", "=", "==", "=>", ">", ">=", ">>", ">>=", "?", "[", "]", "^", "^=", "calldata", "case", "constant", "days", "default", "error", "ether", "external", "gwei", "hours", "immutable", "indexed", "internal", "leave", "memory", "minutes", "override", "private", "public", "revert", "seconds", "storage", "switch", "weeks", "wei", "{", "|", "|=", "||", "}", identifier"#.to_string(), notes: vec![] },
                 Diagnostic { loc: File(0, 164, 166), level: Error, ty: ParserError, message: r#"unrecognised token 'id', expected ";""#.to_string(), notes: vec![] },
                 Diagnostic { loc: File(0, 179, 180), level: Error, ty: ParserError, message: r#"unrecognised token '1', expected "case", "default", "error", "leave", "revert", "switch", identifier"#.to_string(), notes: vec![] },
                 Diagnostic { loc: File(0, 196, 197), level: Error, ty: ParserError, message: r#"unrecognised token '0', expected "!=", "%", "%=", "&", "&&", "&=", "(", ")", "*", "**", "*=", "+", "++", "+=", ",", "-", "--", "-=", ".", "/", "/=", ":", ";", "<", "<<", "<<=", "<=", "=", "==", "=>", ">", ">=", ">>", ">>=", "?", "[", "]", "^", "^=", "calldata", "case", "constant", "days", "default", "error", "ether", "external", "gwei", "hours", "immutable", "indexed", "internal", "leave", "memory", "minutes", "override", "private", "public", "revert", "seconds", "storage", "switch", "weeks", "wei", "{", "|", "|=", "||", "}", identifier"#.to_string(), notes: vec![] },
-                Diagnostic { loc: File(0, 238, 242), level: Error, ty: ParserError, message: r#"unrecognised token 'uint256', expected "!=", "%", "%=", "&", "&&", "&=", "(", ")", "*", "**", "*=", "+", "++", "+=", ",", "-", "--", "-=", ".", "/", "/=", ":", ";", "<", "<<", "<<=", "<=", "=", "==", "=>", ">", ">=", ">>", ">>=", "?", "[", "]", "^", "^=", "calldata", "case", "constant", "days", "default", "error", "ether", "external", "gwei", "hours", "immutable", "indexed", "internal", "leave", "memory", "minutes", "override", "payable", "private", "public", "pure", "return", "returns", "revert", "seconds", "storage", "switch", "view", "virtual", "weeks", "wei", "{", "|", "|=", "||", "}", identifier"#.to_string(), notes: vec![] },
+                Diagnostic { loc: File(0, 238, 242), level: Error, ty: ParserError, message: r#"unrecognised token 'uint256', expected "!=", "%", "%=", "&", "&&", "&=", "(", ")", "*", "**", "*=", "+", "++", "+=", ",", "-", "--", "-=", ".", "/", "/=", ":", ";", "<", "<<", "<<=", "<=", "=", "==", "=>", ">", ">=", ">>", ">>=", "?", "[", "]", "^", "^=", "calldata", "case", "constant", "days", "default", "error", "ether", "external", "gwei", "hours", "immutable", "indexed", "internal", "leave", "memory", "minutes", "override", "private", "public", "revert", "seconds", "storage", "switch", "weeks", "wei", "{", "|", "|=", "||", "}", identifier"#.to_string(), notes: vec![] },
                 Diagnostic { loc: File(0, 292, 293), level: Error, ty: ParserError, message: r#"unrecognised token '0', expected "!=", "%", "%=", "&", "&&", "&=", "(", ")", "*", "**", "*=", "+", "++", "+=", ",", "-", "--", "-=", ".", "/", "/=", ":", ";", "<", "<<", "<<=", "<=", "=", "==", "=>", ">", ">=", ">>", ">>=", "?", "[", "]", "^", "^=", "calldata", "case", "constant", "days", "default", "error", "ether", "external", "gwei", "hours", "immutable", "indexed", "internal", "leave", "memory", "minutes", "override", "private", "public", "revert", "seconds", "storage", "switch", "weeks", "wei", "{", "|", "|=", "||", "}", identifier"#.to_string(), notes: vec![] },
-                Diagnostic { loc: File(0, 334, 338), level: Error, ty: ParserError, message: r#"unrecognised token 'uint256', expected "!=", "%", "%=", "&", "&&", "&=", "(", ")", "*", "**", "*=", "+", "++", "+=", ",", "-", "--", "-=", ".", "/", "/=", ":", ";", "<", "<<", "<<=", "<=", "=", "==", "=>", ">", ">=", ">>", ">>=", "?", "[", "]", "^", "^=", "calldata", "case", "constant", "days", "default", "error", "ether", "external", "gwei", "hours", "immutable", "indexed", "internal", "leave", "memory", "minutes", "override", "payable", "private", "public", "pure", "return", "returns", "revert", "seconds", "storage", "switch", "view", "virtual", "weeks", "wei", "{", "|", "|=", "||", "}", identifier"#.to_string(), notes: vec![] },
+                Diagnostic { loc: File(0, 334, 338), level: Error, ty: ParserError, message: r#"unrecognised token 'uint256', expected "!=", "%", "%=", "&", "&&", "&=", "(", ")", "*", "**", "*=", "+", "++", "+=", ",", "-", "--", "-=", ".", "/", "/=", ":", ";", "<", "<<", "<<=", "<=", "=", "==", "=>", ">", ">=", ">>", ">>=", "?", "[", "]", "^", "^=", "calldata", "case", "constant", "days", "default", "error", "ether", "external", "gwei", "hours", "immutable", "indexed", "internal", "leave", "memory", "minutes", "override", "private", "public", "revert", "seconds", "storage", "switch", "weeks", "wei", "{", "|", "|=", "||", "}", identifier"#.to_string(), notes: vec![] },
                 Diagnostic { loc: File(0, 403, 404), level: Error, ty: ParserError, message: r#"unrecognised token '3', expected "!=", "%", "%=", "&", "&&", "&=", "(", ")", "*", "**", "*=", "+", "++", "+=", ",", "-", "--", "-=", ".", "/", "/=", ":", ";", "<", "<<", "<<=", "<=", "=", "==", "=>", ">", ">=", ">>", ">>=", "?", "[", "]", "^", "^=", "calldata", "case", "constant", "days", "default", "error", "ether", "external", "gwei", "hours", "immutable", "indexed", "internal", "leave", "memory", "minutes", "override", "private", "public", "revert", "seconds", "storage", "switch", "weeks", "wei", "{", "|", "|=", "||", "}", identifier"#.to_string(), notes: vec![] },
                 Diagnostic { loc: File(0, 441, 442), level: Error, ty: ParserError, message: r#"unrecognised token '4', expected "(", "case", "default", "error", "leave", "revert", "switch", identifier"#.to_string(), notes: vec![] },
                 Diagnostic { loc: File(0, 460, 461), level: Error, ty: ParserError, message: r#"unrecognised token '!', expected "!=", "%", "%=", "&", "&&", "&=", ")", "*", "**", "*=", "+", "++", "+=", ",", "-", "--", "-=", ".", "/", "/=", ":", ";", "<", "<<", "<<=", "<=", "=", "==", "=>", ">", ">=", ">>", ">>=", "?", "[", "]", "^", "^=", "calldata", "case", "constant", "days", "default", "error", "ether", "external", "gwei", "hours", "immutable", "indexed", "internal", "leave", "memory", "minutes", "override", "payable", "private", "public", "pure", "return", "returns", "revert", "seconds", "storage", "switch", "view", "virtual", "weeks", "wei", "{", "|", "|=", "||", "}", identifier"#.to_string(), notes: vec![] },
                 Diagnostic { loc: File(0, 482, 483), level: Error, ty: ParserError, message: r#"unrecognised token '3', expected "!=", "%", "%=", "&", "&&", "&=", "(", ")", "*", "**", "*=", "+", "++", "+=", ",", "-", "--", "-=", ".", "/", "/=", ":", ";", "<", "<<", "<<=", "<=", "=", "==", "=>", ">", ">=", ">>", ">>=", "?", "[", "]", "^", "^=", "calldata", "case", "constant", "days", "default", "error", "ether", "external", "gwei", "hours", "immutable", "indexed", "internal", "leave", "memory", "minutes", "override", "private", "public", "revert", "seconds", "storage", "switch", "weeks", "wei", "{", "|", "|=", "||", "}", identifier"#.to_string(), notes: vec![] },
                 Diagnostic { loc: File(0, 495, 502), level: Error, ty: ParserError, message: r#"unrecognised token 'sesa_id', expected ")", ";""#.to_string(), notes: vec![] },
-                Diagnostic { loc: File(0, 518, 522), level: Error, ty: ParserError, message: "unrecognised token 'uint256', expected \"!=\", \"%\", \"%=\", \"&\", \"&&\", \"&=\", \"(\", \")\", \"*\", \"**\", \"*=\", \"+\", \"++\", \"+=\", \",\", \"-\", \"--\", \"-=\", \".\", \"/\", \"/=\", \":\", \";\", \"<\", \"<<\", \"<<=\", \"<=\", \"=\", \"==\", \"=>\", \">\", \">=\", \">>\", \">>=\", \"?\", \"[\", \"]\", \"^\", \"^=\", \"calldata\", \"case\", \"constant\", \"days\", \"default\", \"error\", \"ether\", \"external\", \"gwei\", \"hours\", \"immutable\", \"indexed\", \"internal\", \"leave\", \"memory\", \"minutes\", \"override\", \"payable\", \"private\", \"public\", \"pure\", \"return\", \"returns\", \"revert\", \"seconds\", \"storage\", \"switch\", \"view\", \"virtual\", \"weeks\", \"wei\", \"{\", \"|\", \"|=\", \"||\", \"}\", identifier".to_string(), notes: vec![] },
+                Diagnostic { loc: File(0, 518, 522), level: Error, ty: ParserError, message: "unrecognised token 'uint256', expected \"!=\", \"%\", \"%=\", \"&\", \"&&\", \"&=\", \"(\", \")\", \"*\", \"**\", \"*=\", \"+\", \"++\", \"+=\", \",\", \"-\", \"--\", \"-=\", \".\", \"/\", \"/=\", \":\", \";\", \"<\", \"<<\", \"<<=\", \"<=\", \"=\", \"==\", \"=>\", \">\", \">=\", \">>\", \">>=\", \"?\", \"[\", \"]\", \"^\", \"^=\", \"calldata\", \"case\", \"constant\", \"days\", \"default\", \"error\", \"ether\", \"external\", \"gwei\", \"hours\", \"immutable\", \"indexed\", \"internal\", \"leave\", \"memory\", \"minutes\", \"override\", \"private\", \"public\", \"revert\", \"seconds\", \"storage\", \"switch\", \"weeks\", \"wei\", \"{\", \"|\", \"|=\", \"||\", \"}\", identifier".to_string(), notes: vec![] },
                 Diagnostic { loc: File(0, 530, 531), level: Error, ty: ParserError, message: "unrecognised token 'b', expected \")\", \";\"".to_string(), notes: vec![] },
                 Diagnostic { loc: File(0, 555, 556), level: Error, ty: ParserError, message: "unrecognised token '}', expected \"!\", \"(\", \"+\", \"++\", \"-\", \"--\", \"[\", \"address\", \"assembly\", \"bool\", \"break\", \"byte\", \"bytes\", \"case\", \"continue\", \"default\", \"delete\", \"do\", \"emit\", \"error\", \"false\", \"for\", \"function\", \"if\", \"leave\", \"mapping\", \"new\", \"payable\", \"return\", \"revert\", \"string\", \"switch\", \"this\", \"true\", \"try\", \"type\", \"unchecked\", \"while\", \"{\", \"~\", Bytes, Int, Uint, address, hexnumber, hexstring, identifier, number, rational, string".to_string(), notes: vec![] },
                 Diagnostic { loc: File(0, 557, 558), level: Error, ty: ParserError, message: "unrecognised token '}', expected \"(\", \";\", \"@\", \"[\", \"abstract\", \"address\", \"bool\", \"byte\", \"bytes\", \"case\", \"contract\", \"default\", \"enum\", \"error\", \"event\", \"false\", \"function\", \"import\", \"interface\", \"leave\", \"library\", \"mapping\", \"payable\", \"pragma\", \"string\", \"struct\", \"switch\", \"this\", \"true\", \"type\", \"using\", Bytes, Int, Uint, address, hexnumber, hexstring, identifier, number, rational, string".to_string(), notes: vec![] }

+ 7 - 10
src/bin/idl/mod.rs

@@ -2,6 +2,7 @@
 
 use anchor_syn::idl::{Idl, IdlInstruction, IdlType, IdlTypeDefinitionTy};
 use clap::ArgMatches;
+use itertools::Itertools;
 use serde_json::Value as JsonValue;
 use solang::abi::anchor::discriminator;
 use solang_parser::lexer::is_keyword;
@@ -280,9 +281,13 @@ fn instruction(
             .unwrap()
             .1;
 
+        // The anchor discriminator is what Solidity calls a selector
+        let selector = discriminator(if state { "state" } else { "global" }, &instr.name);
+
         write!(
             f,
-            "\tfunction {}(",
+            "\t@selector([{}])\n\tfunction {}(",
+            selector.iter().map(|v| format!("{:#04x}", v)).join(","),
             if instr.name == "new" {
                 "initialize"
             } else {
@@ -305,15 +310,7 @@ fn instruction(
             )?;
         }
 
-        // The anchor discriminator is what Solidity calls a selector
-        let selector = discriminator(if state { "state" } else { "global" }, &instr.name);
-
-        write!(
-            f,
-            ") selector=hex\"{}\" {}external",
-            hex::encode(selector),
-            if state { "" } else { "view " }
-        )?;
+        write!(f, ") {}external", if state { "" } else { "view " })?;
 
         if let Some(ty) = &instr.returns {
             writeln!(

+ 2 - 2
src/sema/ast.rs

@@ -266,7 +266,7 @@ pub struct Function {
     pub is_accessor: bool,
     pub is_override: Option<(pt::Loc, Vec<usize>)>,
     /// The selector (known as discriminator on Solana/Anchor)
-    pub selector: Option<Vec<u8>>,
+    pub selector: Option<(pt::Loc, Vec<u8>)>,
     /// Was the function declared with a body
     pub has_body: bool,
     /// The resolved body (if any)
@@ -386,7 +386,7 @@ impl Function {
 
     /// Generate selector for this function
     pub fn selector(&self, ns: &Namespace, contract_no: &usize) -> Vec<u8> {
-        if let Some(selector) = &self.selector {
+        if let Some((_, selector)) = &self.selector {
             selector.clone()
         } else if ns.target == Target::Solana {
             match self.ty {

+ 23 - 19
src/sema/contracts.rs

@@ -827,14 +827,12 @@ fn base_function_compatible(
         (cur, func) if cur == func => (),
         (Some(cur_selector), Some(func_selector)) => {
             diagnostics.push(ast::Diagnostic::error_with_note(
-                func.loc,
+                cur_selector.0,
                 format!(
-                    "selector '{}' of function '{}' different from base selector '{}'",
-                    hex::encode(cur_selector),
+                    "selector of function '{}' different from base selector",
                     func.name,
-                    hex::encode(func_selector)
                 ),
-                base.loc,
+                func_selector.0,
                 String::from("location of base function"),
             ));
         }
@@ -842,20 +840,18 @@ fn base_function_compatible(
             diagnostics.push(ast::Diagnostic::error_with_note(
                 func.loc,
                 format!(
-                    "selector of function '{}' must match base selector '{}'",
+                    "selector of function '{}' must match base selector",
                     func.name,
-                    hex::encode(func_selector)
                 ),
-                base.loc,
+                func_selector.0,
                 String::from("location of base function"),
             ));
         }
         (Some(cur_selector), None) => {
             diagnostics.push(ast::Diagnostic::error_with_note(
-                func.loc,
+                cur_selector.0,
                 format!(
-                    "base function needs same selector as selector '{}' of function '{}'",
-                    hex::encode(cur_selector),
+                    "base function needs same selector as selector of function '{}'",
                     func.name,
                 ),
                 base.loc,
@@ -909,9 +905,14 @@ fn resolve_declarations<'a>(
     // resolve function signatures
     for part in &def.parts {
         if let pt::ContractPart::FunctionDefinition(ref f) = &part.part {
-            if let Some(function_no) =
-                functions::contract_function(def, f, &part.doccomments, file_no, ns)
-            {
+            if let Some(function_no) = functions::contract_function(
+                def,
+                f,
+                &part.doccomments,
+                &part.annotations,
+                file_no,
+                ns,
+            ) {
                 if f.body.is_some() {
                     delayed.function_bodies.push(DelayedResolveFunction {
                         contract_no: def.contract_no,
@@ -920,8 +921,6 @@ fn resolve_declarations<'a>(
                         annotations: part.annotations.clone(),
                     });
                 } else {
-                    annotions_not_allowed(&part.annotations, &format!("{} with no body", f.ty), ns);
-
                     function_no_bodies.push(function_no);
                 }
             }
@@ -1220,12 +1219,17 @@ fn verify_unique_selector(contract_no: usize, ns: &mut Namespace) {
 
         // On Solana, concrete contracts have selectors of 8 bytes
         if ns.contracts[contract_no].is_concrete() && selector.len() != selector_len as usize {
+            let loc = if let Some((loc, _)) = &func.selector {
+                loc
+            } else {
+                &func.loc
+            };
+
             diagnostics.push(ast::Diagnostic::error(
-                func.loc,
+                *loc,
                 format!(
-                    "function '{}' selector '{}' must be {} bytes rather than {} bytes",
+                    "function '{}' selector must be {} bytes rather than {} bytes",
                     func.name,
-                    hex::encode(&selector),
                     selector_len,
                     selector.len()
                 ),

+ 1 - 1
src/sema/dotgraphviz.rs

@@ -157,7 +157,7 @@ impl Dot {
             }
         }
 
-        if let Some(selector) = &func.selector {
+        if let Some((_, selector)) = &func.selector {
             labels.push(format!("selector {}", hex::encode(selector)));
         }
 

+ 1 - 1
src/sema/eval.rs

@@ -517,7 +517,7 @@ fn eval_constants_in_expression(
 }
 
 /// Function that takes a BigInt and an expected type. If the number of bits in the type required to represent the BigInt is not suffiecient, it will return a diagnostic.
-fn overflow_check(result: &BigInt, ty: &Type, loc: &Loc) -> Option<Diagnostic> {
+pub(super) fn overflow_check(result: &BigInt, ty: &Type, loc: &Loc) -> Option<Diagnostic> {
     if let Type::Uint(bits) = ty {
         // If the result sign is minus, throw an error.
         if let Sign::Minus = result.sign() {

+ 2 - 2
src/sema/expression.rs

@@ -1567,7 +1567,7 @@ pub fn coerce_number(
 }
 
 /// Resolve the given number literal, multiplied by value of unit
-fn number_literal(
+pub(super) fn number_literal(
     loc: &pt::Loc,
     integer: &str,
     exp: &str,
@@ -2502,7 +2502,7 @@ fn hex_literal(
     }
 }
 
-fn hex_number_literal(
+pub(super) fn hex_number_literal(
     loc: &pt::Loc,
     n: &str,
     ns: &mut Namespace,

+ 136 - 3
src/sema/function_annotation.rs

@@ -1,18 +1,147 @@
 // SPDX-License-Identifier: Apache-2.0
 
 use super::{
-    ast::{ConstructorAnnotation, Diagnostic, Namespace, Type},
+    ast::{ConstructorAnnotation, Diagnostic, Expression, Function, Namespace, Type},
     diagnostics::Diagnostics,
-    expression::{expression, ExprContext, ResolveTo},
+    eval::overflow_check,
+    expression::{expression, hex_number_literal, number_literal, ExprContext, ResolveTo},
     unused_variable::used_variable,
     Symtable,
 };
 use crate::Target;
+use num_bigint::BigInt;
+use num_traits::{One, ToPrimitive};
 use solang_parser::pt::{self, CodeLocation};
 
+/// Resolve the prototype annotation for functions (just the selector). These
+/// annotations can be resolved for functions without a body. This means they
+/// do not need to access the symbol table, like `@seed(foo)` annotations do.
+pub fn function_prototype_annotations(
+    func: &mut Function,
+    annotations: &[&pt::Annotation],
+    ns: &mut Namespace,
+) {
+    let mut diagnostics = Diagnostics::default();
+
+    for annotation in annotations {
+        match annotation.id.name.as_str() {
+            "selector" => function_selector(func, annotation, &mut diagnostics, ns),
+            _ if !func.has_body => {
+                // function_body_annotations() is called iff there is a body
+                diagnostics.push(Diagnostic::error(
+                    annotation.loc,
+                    format!(
+                        "annotation '@{}' not allowed on {} with no body",
+                        annotation.id.name, func.ty
+                    ),
+                ));
+            }
+            _ => {
+                // handled in function_body_annotations()
+            }
+        }
+    }
+
+    ns.diagnostics.extend(diagnostics);
+}
+
+/// Parse the selector from an annotation and assign it to the function
+fn function_selector(
+    func: &mut Function,
+    annotation: &pt::Annotation,
+    diagnostics: &mut Diagnostics,
+    ns: &mut Namespace,
+) {
+    if func.ty != pt::FunctionTy::Function
+        && (!ns.target.is_substrate() || func.ty != pt::FunctionTy::Constructor)
+    {
+        diagnostics.push(Diagnostic::error(
+            annotation.loc,
+            format!("overriding selector not permitted on {}", func.ty),
+        ));
+        return;
+    }
+
+    if !func.is_public() {
+        diagnostics.push(Diagnostic::error(
+            annotation.loc,
+            format!(
+                "overriding selector only permitted on 'public' or 'external' function, not '{}'",
+                func.visibility
+            ),
+        ));
+        return;
+    }
+
+    if let Some((prev, _)) = &func.selector {
+        diagnostics.push(Diagnostic::error_with_note(
+            annotation.loc,
+            format!("duplicate @selector annotation for {}", func.ty),
+            *prev,
+            "previous @selector".into(),
+        ));
+        return;
+    }
+
+    match &annotation.value {
+        pt::Expression::ArrayLiteral(_, values) => {
+            let mut selector = Vec::new();
+
+            for expr in values {
+                let uint8 = Type::Uint(8);
+
+                let expr = match expr {
+                    pt::Expression::HexNumberLiteral(loc, n) => {
+                        hex_number_literal(loc, n, ns, diagnostics, ResolveTo::Type(&uint8))
+                    }
+                    pt::Expression::NumberLiteral(loc, base, exp) => number_literal(
+                        loc,
+                        base,
+                        exp,
+                        ns,
+                        &BigInt::one(),
+                        diagnostics,
+                        ResolveTo::Type(&uint8),
+                    ),
+                    _ => {
+                        diagnostics.push(Diagnostic::error(
+                            expr.loc(),
+                            "literal number expected".into(),
+                        ));
+                        continue;
+                    }
+                };
+
+                if let Ok(Expression::NumberLiteral(loc, _, v)) = &expr {
+                    if let Some(diagnostic) = overflow_check(v, &uint8, loc) {
+                        diagnostics.push(diagnostic);
+                    } else {
+                        selector.push(v.to_u8().unwrap());
+                    }
+                } else {
+                    // Diagnostic already generated
+                    assert!(expr.is_err());
+                }
+            }
+
+            if !diagnostics.any_errors() {
+                func.selector = Some((annotation.loc, selector));
+            }
+        }
+        _ => {
+            diagnostics.push(Diagnostic::error(
+                annotation.value.loc(),
+                "expression must be an array literal".into(),
+            ));
+        }
+    }
+}
+
 /// Collect the seeds, bump, payer, and space for constructors. This is a no-op on Substrate/EVM since
 /// there should be no seed or bump annotations permitted on other targets.
-pub fn function_annotations(
+///
+/// These annotations need a symbol table.
+pub fn function_body_annotations(
     function_no: usize,
     annotations: &[&pt::Annotation],
     symtable: &mut Symtable,
@@ -38,6 +167,10 @@ pub fn function_annotations(
 
     for note in annotations {
         match note.id.name.as_str() {
+            "selector" => {
+                // selectors already done in function_prototype_annotations
+                // without using a symbol table
+            }
             "seed" if is_solana_constructor => {
                 let ty = Type::Slice(Box::new(Type::Bytes(1)));
                 let loc = note.loc;

+ 6 - 111
src/sema/functions.rs

@@ -1,15 +1,12 @@
 // SPDX-License-Identifier: Apache-2.0
 
 use super::{
-    ast::{
-        Diagnostic, Expression, Function, Mutability, Namespace, Parameter, StructType, Symbol,
-        Type,
-    },
+    ast::{Diagnostic, Function, Mutability, Namespace, Parameter, StructType, Symbol, Type},
     contracts::is_base,
     diagnostics::Diagnostics,
-    expression::{expression, ExprContext, ResolveTo},
+    function_annotation::function_prototype_annotations,
     tags::resolve_tags,
-    ContractDefinition, Symtable,
+    ContractDefinition,
 };
 use crate::Target;
 use solang_parser::{
@@ -23,6 +20,7 @@ pub fn contract_function(
     contract: &ContractDefinition,
     func: &pt::FunctionDefinition,
     tags: &[DocComment],
+    annotations: &[&pt::Annotation],
     file_no: usize,
     ns: &mut Namespace,
 ) -> Option<usize> {
@@ -113,7 +111,6 @@ pub fn contract_function(
     let mut visibility: Option<pt::Visibility> = None;
     let mut is_virtual: Option<pt::Loc> = None;
     let mut is_override: Option<(pt::Loc, Vec<usize>)> = None;
-    let mut has_selector: Option<&pt::Expression> = None;
 
     for a in &func.attributes {
         match &a {
@@ -176,34 +173,6 @@ pub fn contract_function(
 
                 is_virtual = Some(*loc);
             }
-            pt::FunctionAttribute::NameValue(loc, name, value) => {
-                if name.name != "selector" {
-                    ns.diagnostics.push(Diagnostic::error(
-                        name.loc,
-                        format!("function attribute '{}' not supported", name.name),
-                    ));
-                    success = false;
-                } else if let Some(prev_loc) = &has_selector {
-                    ns.diagnostics.push(Diagnostic::error_with_note(
-                        *loc,
-                        "function redeclared attribute 'selector'".to_string(),
-                        prev_loc.loc(),
-                        "location of previous declaration of 'selector'".to_string(),
-                    ));
-                    success = false;
-                } else {
-                    if ns.target == Target::Solana {
-                        ns.diagnostics.push(Diagnostic::warning(
-                            *loc,
-                            "Selector (or discriminator) overriding may not have the \
-                              desired effect. The metadata file does not contains the overridden \
-                              selector, so the contract will not function."
-                                .to_string(),
-                        ));
-                    }
-                    has_selector = Some(value);
-                }
-            }
             pt::FunctionAttribute::Override(loc, bases) => {
                 if let Some((prev_loc, _)) = &is_override {
                     ns.diagnostics.push(Diagnostic::error_with_note(
@@ -334,74 +303,6 @@ pub fn contract_function(
 
     let mut diagnostics = Diagnostics::default();
 
-    let selector = if let Some(selector) = has_selector {
-        if func.ty != pt::FunctionTy::Function
-            && (!ns.target.is_substrate() || func.ty != pt::FunctionTy::Constructor)
-        {
-            ns.diagnostics.push(Diagnostic::error(
-                selector.loc(),
-                format!("overriding selector not permitted on {}", func.ty),
-            ));
-
-            None
-        } else if !matches!(
-            visibility,
-            pt::Visibility::External(_) | pt::Visibility::Public(_)
-        ) {
-            ns.diagnostics.push(Diagnostic::error(
-                selector.loc(),
-                format!(
-                    "overriding selector only permitted on 'public' or 'external' function, not '{}'",
-                    visibility
-                ),
-            ));
-
-            None
-        } else {
-            let context = ExprContext {
-                file_no,
-                constant: true,
-                ..Default::default()
-            };
-
-            match expression(
-                selector,
-                &context,
-                ns,
-                &mut Symtable::new(),
-                &mut diagnostics,
-                ResolveTo::Unknown,
-            ) {
-                Ok(Expression::BytesLiteral(_, _, v)) => {
-                    if ns.target != Target::Solana && v.len() != 4 {
-                        ns.diagnostics.push(Diagnostic::error(
-                            selector.loc(),
-                            format!("selector is {} bytes, 4 bytes expected", v.len()),
-                        ));
-                        success = false;
-                        None
-                    } else {
-                        Some(v)
-                    }
-                }
-                Ok(_) => {
-                    ns.diagnostics.push(Diagnostic::error(
-                        selector.loc(),
-                        "hex literal of the form 'hex\"1234abcdef\"' expected".to_string(),
-                    ));
-                    success = false;
-                    None
-                }
-                Err(_) => {
-                    success = false;
-                    None
-                }
-            }
-        }
-    } else {
-        None
-    };
-
     let (params, params_success) = resolve_params(
         &func.params,
         storage_allowed,
@@ -567,7 +468,8 @@ pub fn contract_function(
     fdecl.is_virtual = is_virtual;
     fdecl.is_override = is_override;
     fdecl.has_body = func.body.is_some();
-    fdecl.selector = selector;
+
+    function_prototype_annotations(&mut fdecl, annotations, ns);
 
     if func.ty == pt::FunctionTy::Constructor {
         // In the eth solidity only one constructor is allowed
@@ -827,13 +729,6 @@ pub fn function(
                 ));
                 success = false;
             }
-            pt::FunctionAttribute::NameValue(loc, name, _) => {
-                ns.diagnostics.push(Diagnostic::error(
-                    *loc,
-                    format!("attribute '{}' not supported", name.name),
-                ));
-                success = false;
-            }
             pt::FunctionAttribute::Error(_) => {
                 success = false;
             }

+ 2 - 2
src/sema/statements.rs

@@ -11,7 +11,7 @@ use super::expression::{
 };
 use super::symtable::{LoopScopes, Symtable};
 use crate::sema::builtin;
-use crate::sema::function_annotation::function_annotations;
+use crate::sema::function_annotation::function_body_annotations;
 use crate::sema::symtable::{VariableInitializer, VariableUsage};
 use crate::sema::unused_variable::{assigned_variable, check_function_call, used_variable};
 use crate::sema::yul::resolve_inline_assembly;
@@ -66,7 +66,7 @@ pub fn resolve_function_body(
         }
     }
 
-    function_annotations(function_no, annotations, &mut symtable, &context, ns);
+    function_body_annotations(function_no, annotations, &mut symtable, &context, ns);
 
     // now that the function arguments have been resolved, we can resolve the bases for
     // constructors.

+ 15 - 15
tests/contract_testcases/evm/selector_override.dot

@@ -1,19 +1,19 @@
 strict digraph "tests/contract_testcases/evm/selector_override.sol" {
-	contract [label="contract selector\ntests/contract_testcases/evm/selector_override.sol:1:1-8:2"]
-	node_2 [label="constructor \ncontract: selector\ntests/contract_testcases/evm/selector_override.sol:2:2-34\nsignature ()\nvisibility public\nmutability nonpayable"]
-	m [label="modifier m\ncontract: selector\ntests/contract_testcases/evm/selector_override.sol:3:2-29\nmutability nonpayable"]
-	underscore [label="undersore\ntests/contract_testcases/evm/selector_override.sol:3:31-32"]
-	node_5 [label="receive \ncontract: selector\ntests/contract_testcases/evm/selector_override.sol:4:2-44\nmutability payable"]
-	node_6 [label="fallback \ncontract: selector\ntests/contract_testcases/evm/selector_override.sol:5:2-39\nmutability nonpayable"]
-	i [label="function i\ncontract: selector\ntests/contract_testcases/evm/selector_override.sol:6:2-45\nsignature i()\nvisibility internal\nmutability nonpayable"]
-	p [label="function p\ncontract: selector\ntests/contract_testcases/evm/selector_override.sol:7:2-44\nsignature p()\nvisibility private\nmutability nonpayable"]
-	diagnostic [label="found contract 'selector'\nlevel Debug\ntests/contract_testcases/evm/selector_override.sol:1:1-8:2"]
-	diagnostic_11 [label="overriding selector not permitted on constructor\nlevel Error\ntests/contract_testcases/evm/selector_override.sol:2:25-34"]
-	diagnostic_12 [label="overriding selector not permitted on modifier\nlevel Error\ntests/contract_testcases/evm/selector_override.sol:3:24-29"]
-	diagnostic_13 [label="overriding selector not permitted on receive\nlevel Error\ntests/contract_testcases/evm/selector_override.sol:4:38-44"]
-	diagnostic_14 [label="overriding selector not permitted on fallback\nlevel Error\ntests/contract_testcases/evm/selector_override.sol:5:31-39"]
-	diagnostic_15 [label="overriding selector only permitted on 'public' or 'external' function, not 'internal'\nlevel Error\ntests/contract_testcases/evm/selector_override.sol:6:35-45"]
-	diagnostic_16 [label="overriding selector only permitted on 'public' or 'external' function, not 'private'\nlevel Error\ntests/contract_testcases/evm/selector_override.sol:7:34-44"]
+	contract [label="contract selector\ntests/contract_testcases/evm/selector_override.sol:1:1-14:2"]
+	node_2 [label="constructor \ncontract: selector\ntests/contract_testcases/evm/selector_override.sol:3:2-16\nsignature ()\nvisibility public\nmutability nonpayable"]
+	m [label="modifier m\ncontract: selector\ntests/contract_testcases/evm/selector_override.sol:5:2-15\nmutability nonpayable"]
+	underscore [label="undersore\ntests/contract_testcases/evm/selector_override.sol:5:16-17"]
+	node_5 [label="receive \ncontract: selector\ntests/contract_testcases/evm/selector_override.sol:7:2-28\nmutability payable"]
+	node_6 [label="fallback \ncontract: selector\ntests/contract_testcases/evm/selector_override.sol:9:2-21\nmutability nonpayable"]
+	i [label="function i\ncontract: selector\ntests/contract_testcases/evm/selector_override.sol:11:2-23\nsignature i()\nvisibility internal\nmutability nonpayable"]
+	p [label="function p\ncontract: selector\ntests/contract_testcases/evm/selector_override.sol:13:2-22\nsignature p()\nvisibility private\nmutability nonpayable"]
+	diagnostic [label="found contract 'selector'\nlevel Debug\ntests/contract_testcases/evm/selector_override.sol:1:1-14:2"]
+	diagnostic_11 [label="overriding selector not permitted on constructor\nlevel Error\ntests/contract_testcases/evm/selector_override.sol:2:2-25"]
+	diagnostic_12 [label="overriding selector not permitted on modifier\nlevel Error\ntests/contract_testcases/evm/selector_override.sol:4:2-16"]
+	diagnostic_13 [label="overriding selector not permitted on receive\nlevel Error\ntests/contract_testcases/evm/selector_override.sol:6:2-16"]
+	diagnostic_14 [label="overriding selector not permitted on fallback\nlevel Error\ntests/contract_testcases/evm/selector_override.sol:8:2-20"]
+	diagnostic_15 [label="overriding selector only permitted on 'public' or 'external' function, not 'internal'\nlevel Error\ntests/contract_testcases/evm/selector_override.sol:10:2-25"]
+	diagnostic_16 [label="overriding selector only permitted on 'public' or 'external' function, not 'private'\nlevel Error\ntests/contract_testcases/evm/selector_override.sol:12:2-25"]
 	contracts -> contract
 	contract -> node_2 [label="constructor"]
 	contract -> m [label="modifier"]

+ 12 - 6
tests/contract_testcases/evm/selector_override.sol

@@ -1,8 +1,14 @@
 contract selector {
-	constructor() selector=hex"abcd" {}
-	modifier m() selector=hex"" {_;}
-	receive() payable external selector=hex"1" {}
-	fallback() external selector=hex"abc" {}
-	function i() internal selector = hex"ab_dd" {}
-	function p() private selector = hex"ab_dd" {}
+	@selector([0xab, 0xcd])
+	constructor() {}
+	@selector([x])
+	modifier m() {_;}
+	@selector([1])
+	receive() payable external {}
+	@selector([0xabc])
+	fallback() external {}
+	@selector([0xab, 0xdd])
+	function i() internal {}
+	@selector([0xab, 0xdd])
+	function p() private {}
 }

+ 1 - 1
tests/contract_testcases/solana/annotations_bad.dot

@@ -52,7 +52,7 @@ strict digraph "tests/contract_testcases/solana/annotations_bad.sol" {
 	diagnostic_57 [label="annotations not allowed on type\nlevel Error\ntests/contract_testcases/solana/annotations_bad.sol:53:2-10"]
 	diagnostic_58 [label="unknown annotation method for constructor\nlevel Error\ntests/contract_testcases/solana/annotations_bad.sol:56:2-14"]
 	diagnostic_59 [label="unknown annotation fn for function\nlevel Error\ntests/contract_testcases/solana/annotations_bad.sol:60:2-31"]
-	diagnostic_60 [label="annotations not allowed on function with no body\nlevel Error\ntests/contract_testcases/solana/annotations_bad.sol:63:2-27"]
+	diagnostic_60 [label="annotation '@annotation' not allowed on function with no body\nlevel Error\ntests/contract_testcases/solana/annotations_bad.sol:63:2-27"]
 	enums -> EB
 	enums -> e
 	enums -> f

+ 45 - 33
tests/contract_testcases/solana/functions/selector_override.dot

@@ -1,26 +1,32 @@
 strict digraph "tests/contract_testcases/solana/functions/selector_override.sol" {
-	contract [label="contract selector\ntests/contract_testcases/solana/functions/selector_override.sol:1:1-8:2"]
-	node_2 [label="constructor \ncontract: selector\ntests/contract_testcases/solana/functions/selector_override.sol:2:2-34\nsignature ()\nvisibility public\nmutability nonpayable"]
-	m [label="modifier m\ncontract: selector\ntests/contract_testcases/solana/functions/selector_override.sol:3:2-29\nmutability nonpayable"]
-	underscore [label="undersore\ntests/contract_testcases/solana/functions/selector_override.sol:3:31-32"]
-	node_5 [label="receive \ncontract: selector\ntests/contract_testcases/solana/functions/selector_override.sol:4:2-44\nmutability payable"]
-	node_6 [label="fallback \ncontract: selector\ntests/contract_testcases/solana/functions/selector_override.sol:5:2-39\nmutability nonpayable"]
-	i [label="function i\ncontract: selector\ntests/contract_testcases/solana/functions/selector_override.sol:6:2-45\nsignature i()\nvisibility internal\nmutability nonpayable"]
-	p [label="function p\ncontract: selector\ntests/contract_testcases/solana/functions/selector_override.sol:7:2-44\nsignature p()\nvisibility private\nmutability nonpayable"]
-	diagnostic [label="found contract 'selector'\nlevel Debug\ntests/contract_testcases/solana/functions/selector_override.sol:1:1-8:2"]
-	diagnostic_11 [label="Selector (or discriminator) overriding may not have the desired effect. The metadata file does not contains the overridden selector, so the contract will not function.\nlevel Warning\ntests/contract_testcases/solana/functions/selector_override.sol:2:16-34"]
-	diagnostic_12 [label="overriding selector not permitted on constructor\nlevel Error\ntests/contract_testcases/solana/functions/selector_override.sol:2:25-34"]
-	diagnostic_13 [label="Selector (or discriminator) overriding may not have the desired effect. The metadata file does not contains the overridden selector, so the contract will not function.\nlevel Warning\ntests/contract_testcases/solana/functions/selector_override.sol:3:15-29"]
-	diagnostic_14 [label="overriding selector not permitted on modifier\nlevel Error\ntests/contract_testcases/solana/functions/selector_override.sol:3:24-29"]
-	diagnostic_15 [label="target solana does not support receive() functions, see https://solang.readthedocs.io/en/latest/language/functions.html#fallback-and-receive-function\nlevel Error\ntests/contract_testcases/solana/functions/selector_override.sol:4:2-44"]
-	diagnostic_16 [label="Selector (or discriminator) overriding may not have the desired effect. The metadata file does not contains the overridden selector, so the contract will not function.\nlevel Warning\ntests/contract_testcases/solana/functions/selector_override.sol:4:29-44"]
-	diagnostic_17 [label="overriding selector not permitted on receive\nlevel Error\ntests/contract_testcases/solana/functions/selector_override.sol:4:38-44"]
-	diagnostic_18 [label="Selector (or discriminator) overriding may not have the desired effect. The metadata file does not contains the overridden selector, so the contract will not function.\nlevel Warning\ntests/contract_testcases/solana/functions/selector_override.sol:5:22-39"]
-	diagnostic_19 [label="overriding selector not permitted on fallback\nlevel Error\ntests/contract_testcases/solana/functions/selector_override.sol:5:31-39"]
-	diagnostic_20 [label="Selector (or discriminator) overriding may not have the desired effect. The metadata file does not contains the overridden selector, so the contract will not function.\nlevel Warning\ntests/contract_testcases/solana/functions/selector_override.sol:6:24-45"]
-	diagnostic_21 [label="overriding selector only permitted on 'public' or 'external' function, not 'internal'\nlevel Error\ntests/contract_testcases/solana/functions/selector_override.sol:6:35-45"]
-	diagnostic_22 [label="Selector (or discriminator) overriding may not have the desired effect. The metadata file does not contains the overridden selector, so the contract will not function.\nlevel Warning\ntests/contract_testcases/solana/functions/selector_override.sol:7:23-44"]
-	diagnostic_23 [label="overriding selector only permitted on 'public' or 'external' function, not 'private'\nlevel Error\ntests/contract_testcases/solana/functions/selector_override.sol:7:34-44"]
+	contract [label="contract selector\ntests/contract_testcases/solana/functions/selector_override.sol:1:1-14:2"]
+	node_2 [label="constructor \ncontract: selector\ntests/contract_testcases/solana/functions/selector_override.sol:3:2-16\nsignature ()\nvisibility public\nmutability nonpayable"]
+	m [label="modifier m\ncontract: selector\ntests/contract_testcases/solana/functions/selector_override.sol:5:2-15\nmutability nonpayable"]
+	underscore [label="undersore\ntests/contract_testcases/solana/functions/selector_override.sol:5:16-17"]
+	node_5 [label="receive \ncontract: selector\ntests/contract_testcases/solana/functions/selector_override.sol:7:2-28\nmutability payable"]
+	node_6 [label="fallback \ncontract: selector\ntests/contract_testcases/solana/functions/selector_override.sol:9:2-21\nmutability nonpayable"]
+	i [label="function i\ncontract: selector\ntests/contract_testcases/solana/functions/selector_override.sol:11:2-23\nsignature i()\nvisibility internal\nmutability nonpayable"]
+	p [label="function p\ncontract: selector\ntests/contract_testcases/solana/functions/selector_override.sol:13:2-22\nsignature p()\nvisibility private\nmutability nonpayable"]
+	contract_9 [label="contract TooLarge\ntests/contract_testcases/solana/functions/selector_override.sol:16:1-26:2"]
+	get_foo [label="function get_foo\ncontract: TooLarge\ntests/contract_testcases/solana/functions/selector_override.sol:18:5-49\nsignature get_foo()\nvisibility public\nmutability pure"]
+	returns [label="returns\nint256 "]
+	return [label="return\ntests/contract_testcases/solana/functions/selector_override.sol:19:9-19"]
+	number_literal [label="int256 literal: 102\ntests/contract_testcases/solana/functions/selector_override.sol:19:16-19"]
+	get_bar [label="function get_bar\ncontract: TooLarge\ntests/contract_testcases/solana/functions/selector_override.sol:23:5-49\nsignature get_bar()\nvisibility public\nmutability pure"]
+	returns_15 [label="returns\nint256 "]
+	return_16 [label="return\ntests/contract_testcases/solana/functions/selector_override.sol:24:9-19"]
+	number_literal_17 [label="int256 literal: 105\ntests/contract_testcases/solana/functions/selector_override.sol:24:16-19"]
+	diagnostic [label="found contract 'selector'\nlevel Debug\ntests/contract_testcases/solana/functions/selector_override.sol:1:1-14:2"]
+	diagnostic_20 [label="overriding selector not permitted on constructor\nlevel Error\ntests/contract_testcases/solana/functions/selector_override.sol:2:2-25"]
+	diagnostic_21 [label="overriding selector not permitted on modifier\nlevel Error\ntests/contract_testcases/solana/functions/selector_override.sol:4:2-16"]
+	diagnostic_22 [label="overriding selector not permitted on receive\nlevel Error\ntests/contract_testcases/solana/functions/selector_override.sol:6:2-16"]
+	diagnostic_23 [label="target solana does not support receive() functions, see https://solang.readthedocs.io/en/latest/language/functions.html#fallback-and-receive-function\nlevel Error\ntests/contract_testcases/solana/functions/selector_override.sol:7:2-28"]
+	diagnostic_24 [label="overriding selector not permitted on fallback\nlevel Error\ntests/contract_testcases/solana/functions/selector_override.sol:8:2-20"]
+	diagnostic_25 [label="overriding selector only permitted on 'public' or 'external' function, not 'internal'\nlevel Error\ntests/contract_testcases/solana/functions/selector_override.sol:10:2-25"]
+	diagnostic_26 [label="overriding selector only permitted on 'public' or 'external' function, not 'private'\nlevel Error\ntests/contract_testcases/solana/functions/selector_override.sol:12:2-25"]
+	diagnostic_27 [label="found contract 'TooLarge'\nlevel Debug\ntests/contract_testcases/solana/functions/selector_override.sol:16:1-26:2"]
+	diagnostic_28 [label="value 256 does not fit into type uint8.\nlevel Error\ntests/contract_testcases/solana/functions/selector_override.sol:17:25-28"]
+	diagnostic_29 [label="value 2744 does not fit into type uint8.\nlevel Error\ntests/contract_testcases/solana/functions/selector_override.sol:22:34-39"]
 	contracts -> contract
 	contract -> node_2 [label="constructor"]
 	contract -> m [label="modifier"]
@@ -29,18 +35,24 @@ strict digraph "tests/contract_testcases/solana/functions/selector_override.sol"
 	contract -> node_6 [label="fallback"]
 	contract -> i [label="function"]
 	contract -> p [label="function"]
+	contracts -> contract_9
+	contract_9 -> get_foo [label="function"]
+	get_foo -> returns [label="returns"]
+	get_foo -> return [label="body"]
+	return -> number_literal [label="expr"]
+	contract_9 -> get_bar [label="function"]
+	get_bar -> returns_15 [label="returns"]
+	get_bar -> return_16 [label="body"]
+	return_16 -> number_literal_17 [label="expr"]
 	diagnostics -> diagnostic [label="Debug"]
-	diagnostics -> diagnostic_11 [label="Warning"]
-	diagnostics -> diagnostic_12 [label="Error"]
-	diagnostics -> diagnostic_13 [label="Warning"]
-	diagnostics -> diagnostic_14 [label="Error"]
-	diagnostics -> diagnostic_15 [label="Error"]
-	diagnostics -> diagnostic_16 [label="Warning"]
-	diagnostics -> diagnostic_17 [label="Error"]
-	diagnostics -> diagnostic_18 [label="Warning"]
-	diagnostics -> diagnostic_19 [label="Error"]
-	diagnostics -> diagnostic_20 [label="Warning"]
+	diagnostics -> diagnostic_20 [label="Error"]
 	diagnostics -> diagnostic_21 [label="Error"]
-	diagnostics -> diagnostic_22 [label="Warning"]
+	diagnostics -> diagnostic_22 [label="Error"]
 	diagnostics -> diagnostic_23 [label="Error"]
+	diagnostics -> diagnostic_24 [label="Error"]
+	diagnostics -> diagnostic_25 [label="Error"]
+	diagnostics -> diagnostic_26 [label="Error"]
+	diagnostics -> diagnostic_27 [label="Debug"]
+	diagnostics -> diagnostic_28 [label="Error"]
+	diagnostics -> diagnostic_29 [label="Error"]
 }

+ 24 - 6
tests/contract_testcases/solana/functions/selector_override.sol

@@ -1,8 +1,26 @@
 contract selector {
-	constructor() selector=hex"abcd" {}
-	modifier m() selector=hex"" {_;}
-	receive() payable external selector=hex"1" {}
-	fallback() external selector=hex"abc" {}
-	function i() internal selector = hex"ab_dd" {}
-	function p() private selector = hex"ab_dd" {}
+	@selector([0xab, 0xcd])
+	constructor() {}
+	@selector([x])
+	modifier m() {_;}
+	@selector([1])
+	receive() payable external {}
+	@selector([0xabc])
+	fallback() external {}
+	@selector([0xab, 0xdd])
+	function i() internal {}
+	@selector([0xab, 0xdd])
+	function p() private {}
+}
+
+contract TooLarge {
+    @selector([1, 2, 3, 256])
+    function get_foo() pure public returns (int) {
+        return 102;
+    }
+
+    @selector([0x05, 0x06, 0x07, 0xab8])
+    function get_bar() pure public returns (int) {
+        return 105;
+    }
 }

+ 51 - 67
tests/contract_testcases/solana/functions/selectors-must-be-different.dot

@@ -1,51 +1,43 @@
 strict digraph "tests/contract_testcases/solana/functions/selectors-must-be-different.sol" {
-	contract [label="contract c\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:1:1-7:2"]
-	f1 [label="function f1\ncontract: c\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:2:2-39\nsignature f1()\nvisibility public\nmutability nonpayable\nselector 01"]
-	f2 [label="function f2\ncontract: c\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:4:2-39\nsignature f2()\nvisibility public\nmutability nonpayable\nselector 01"]
-	f3 [label="function f3\ncontract: c\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:6:2-39\nsignature f3()\nvisibility public\nmutability nonpayable\nselector 01"]
-	contract_5 [label="contract d\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:9:1-14:2"]
-	var [label="variable c\nvisibility public\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:10:2-14"]
-	c [label="function c\ncontract: d\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:10:13-14\nsignature c()\nvisibility public\nmutability view"]
+	contract [label="contract c\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:1:1-10:2"]
+	f1 [label="function f1\ncontract: c\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:3:2-22\nsignature f1()\nvisibility public\nmutability nonpayable\nselector 01"]
+	f2 [label="function f2\ncontract: c\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:6:2-22\nsignature f2()\nvisibility public\nmutability nonpayable\nselector 01"]
+	f3 [label="function f3\ncontract: c\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:9:2-22\nsignature f3()\nvisibility public\nmutability nonpayable\nselector 01"]
+	contract_5 [label="contract d\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:12:1-18:2"]
+	var [label="variable c\nvisibility public\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:13:2-14"]
+	c [label="function c\ncontract: d\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:13:13-14\nsignature c()\nvisibility public\nmutability view"]
 	returns [label="returns\nint256 "]
 	return [label="return\nimplicit"]
 	storage_load [label="storage load int256\nimplicit"]
 	storage_var [label="storage variable\nd.c\nint256 storage\nimplicit"]
-	f1_12 [label="function f1\ncontract: d\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:13:2-53\nsignature f1()\nvisibility public\nmutability nonpayable\nselector 13fbd725feff6e10"]
-	contract_13 [label="contract e\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:16:1-19:2"]
-	f1_14 [label="function f1\ncontract: e\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:18:2-39\nsignature f1()\nvisibility public\nmutability nonpayable\nselector 01"]
-	contract_15 [label="contract f\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:21:1-26:2"]
-	f1_16 [label="function f1\ncontract: f\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:23:2-53\nsignature f1()\nvisibility public\nmutability nonpayable\nselector 41424344caffee00"]
-	f2_17 [label="function f2\ncontract: f\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:24:2-53\nsignature f2()\nvisibility public\nmutability nonpayable\nselector 41424344caffee00"]
-	f3_18 [label="function f3\ncontract: f\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:25:2-22\nsignature f3()\nvisibility public\nmutability nonpayable"]
-	contract_19 [label="contract g\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:28:1-32:2"]
-	f1_20 [label="function f1\ncontract: g\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:29:2-22\nsignature f1()\nvisibility public\nmutability nonpayable"]
-	f3_21 [label="function f3\ncontract: g\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:31:2-53\nsignature f3()\nvisibility public\nmutability nonpayable\nselector 1b494cee9c541e94"]
-	diagnostic [label="found abstract contract 'c'\nlevel Debug\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:1:1-7:2"]
-	diagnostic_24 [label="Selector (or discriminator) overriding may not have the desired effect. The metadata file does not contains the overridden selector, so the contract will not function.\nlevel Warning\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:2:16-32"]
-	diagnostic_25 [label="function 'f2' selector is the same as function 'f1'\nlevel Error\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:4:2-39"]
-	note [label="definition of function 'f1'\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:2:2-39"]
-	diagnostic_27 [label="Selector (or discriminator) overriding may not have the desired effect. The metadata file does not contains the overridden selector, so the contract will not function.\nlevel Warning\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:4:16-32"]
-	diagnostic_28 [label="function 'f3' selector is the same as function 'f1'\nlevel Error\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:6:2-39"]
-	note_29 [label="definition of function 'f1'\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:2:2-39"]
-	diagnostic_30 [label="Selector (or discriminator) overriding may not have the desired effect. The metadata file does not contains the overridden selector, so the contract will not function.\nlevel Warning\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:6:16-32"]
-	diagnostic_31 [label="found contract 'd'\nlevel Debug\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:9:1-14:2"]
-	diagnostic_32 [label="c is already defined as a contract name\nlevel Warning\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:10:13-14"]
-	note_33 [label="location of previous definition\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:1:1-7:2"]
-	diagnostic_34 [label="function 'f1' selector is the same as function 'c'\nlevel Error\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:13:2-53"]
-	note_35 [label="definition of function 'c'\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:10:13-14"]
-	diagnostic_36 [label="Selector (or discriminator) overriding may not have the desired effect. The metadata file does not contains the overridden selector, so the contract will not function.\nlevel Warning\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:13:16-46"]
-	diagnostic_37 [label="found contract 'e'\nlevel Debug\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:16:1-19:2"]
-	diagnostic_38 [label="function 'f1' selector '01' must be 8 bytes rather than 1 bytes\nlevel Error\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:18:2-39"]
-	diagnostic_39 [label="Selector (or discriminator) overriding may not have the desired effect. The metadata file does not contains the overridden selector, so the contract will not function.\nlevel Warning\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:18:16-32"]
-	diagnostic_40 [label="found contract 'f'\nlevel Debug\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:21:1-26:2"]
-	diagnostic_41 [label="Selector (or discriminator) overriding may not have the desired effect. The metadata file does not contains the overridden selector, so the contract will not function.\nlevel Warning\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:23:16-46"]
-	diagnostic_42 [label="function 'f2' selector is the same as function 'f1'\nlevel Error\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:24:2-53"]
-	note_43 [label="definition of function 'f1'\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:23:2-53"]
-	diagnostic_44 [label="Selector (or discriminator) overriding may not have the desired effect. The metadata file does not contains the overridden selector, so the contract will not function.\nlevel Warning\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:24:16-46"]
-	diagnostic_45 [label="found contract 'g'\nlevel Debug\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:28:1-32:2"]
-	diagnostic_46 [label="function 'f3' selector is the same as function 'f1'\nlevel Error\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:31:2-53"]
-	note_47 [label="definition of function 'f1'\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:29:2-22"]
-	diagnostic_48 [label="Selector (or discriminator) overriding may not have the desired effect. The metadata file does not contains the overridden selector, so the contract will not function.\nlevel Warning\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:31:16-46"]
+	f1_12 [label="function f1\ncontract: d\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:17:2-22\nsignature f1()\nvisibility public\nmutability nonpayable\nselector 13fbd725feff6e10"]
+	contract_13 [label="contract e\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:20:1-24:2"]
+	f1_14 [label="function f1\ncontract: e\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:23:2-22\nsignature f1()\nvisibility public\nmutability nonpayable\nselector 01"]
+	contract_15 [label="contract f\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:26:1-33:2"]
+	f1_16 [label="function f1\ncontract: f\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:29:2-22\nsignature f1()\nvisibility public\nmutability nonpayable\nselector 41424344caffee00"]
+	f2_17 [label="function f2\ncontract: f\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:31:2-22\nsignature f2()\nvisibility public\nmutability nonpayable\nselector 41424344caffee00"]
+	f3_18 [label="function f3\ncontract: f\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:32:2-22\nsignature f3()\nvisibility public\nmutability nonpayable"]
+	contract_19 [label="contract g\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:35:1-40:2"]
+	f1_20 [label="function f1\ncontract: g\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:36:2-22\nsignature f1()\nvisibility public\nmutability nonpayable"]
+	f3_21 [label="function f3\ncontract: g\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:39:2-22\nsignature f3()\nvisibility public\nmutability nonpayable\nselector 1b494cee9c541e94"]
+	diagnostic [label="found abstract contract 'c'\nlevel Debug\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:1:1-10:2"]
+	diagnostic_24 [label="function 'f2' selector is the same as function 'f1'\nlevel Error\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:6:2-22"]
+	note [label="definition of function 'f1'\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:3:2-22"]
+	diagnostic_26 [label="function 'f3' selector is the same as function 'f1'\nlevel Error\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:9:2-22"]
+	note_27 [label="definition of function 'f1'\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:3:2-22"]
+	diagnostic_28 [label="found contract 'd'\nlevel Debug\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:12:1-18:2"]
+	diagnostic_29 [label="c is already defined as a contract name\nlevel Warning\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:13:13-14"]
+	note_30 [label="location of previous definition\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:1:1-10:2"]
+	diagnostic_31 [label="function 'f1' selector is the same as function 'c'\nlevel Error\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:17:2-22"]
+	note_32 [label="definition of function 'c'\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:13:13-14"]
+	diagnostic_33 [label="found contract 'e'\nlevel Debug\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:20:1-24:2"]
+	diagnostic_34 [label="function 'f1' selector must be 8 bytes rather than 1 bytes\nlevel Error\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:22:2-16"]
+	diagnostic_35 [label="found contract 'f'\nlevel Debug\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:26:1-33:2"]
+	diagnostic_36 [label="function 'f2' selector is the same as function 'f1'\nlevel Error\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:31:2-22"]
+	note_37 [label="definition of function 'f1'\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:29:2-22"]
+	diagnostic_38 [label="found contract 'g'\nlevel Debug\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:35:1-40:2"]
+	diagnostic_39 [label="function 'f3' selector is the same as function 'f1'\nlevel Error\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:39:2-22"]
+	note_40 [label="definition of function 'f1'\ntests/contract_testcases/solana/functions/selectors-must-be-different.sol:36:2-22"]
 	contracts -> contract
 	contract -> f1 [label="function"]
 	contract -> f2 [label="function"]
@@ -68,29 +60,21 @@ strict digraph "tests/contract_testcases/solana/functions/selectors-must-be-diff
 	contract_19 -> f1_20 [label="function"]
 	contract_19 -> f3_21 [label="function"]
 	diagnostics -> diagnostic [label="Debug"]
-	diagnostics -> diagnostic_24 [label="Warning"]
-	diagnostics -> diagnostic_25 [label="Error"]
-	diagnostic_25 -> note [label="note"]
-	diagnostics -> diagnostic_27 [label="Warning"]
-	diagnostics -> diagnostic_28 [label="Error"]
-	diagnostic_28 -> note_29 [label="note"]
-	diagnostics -> diagnostic_30 [label="Warning"]
-	diagnostics -> diagnostic_31 [label="Debug"]
-	diagnostics -> diagnostic_32 [label="Warning"]
-	diagnostic_32 -> note_33 [label="note"]
+	diagnostics -> diagnostic_24 [label="Error"]
+	diagnostic_24 -> note [label="note"]
+	diagnostics -> diagnostic_26 [label="Error"]
+	diagnostic_26 -> note_27 [label="note"]
+	diagnostics -> diagnostic_28 [label="Debug"]
+	diagnostics -> diagnostic_29 [label="Warning"]
+	diagnostic_29 -> note_30 [label="note"]
+	diagnostics -> diagnostic_31 [label="Error"]
+	diagnostic_31 -> note_32 [label="note"]
+	diagnostics -> diagnostic_33 [label="Debug"]
 	diagnostics -> diagnostic_34 [label="Error"]
-	diagnostic_34 -> note_35 [label="note"]
-	diagnostics -> diagnostic_36 [label="Warning"]
-	diagnostics -> diagnostic_37 [label="Debug"]
-	diagnostics -> diagnostic_38 [label="Error"]
-	diagnostics -> diagnostic_39 [label="Warning"]
-	diagnostics -> diagnostic_40 [label="Debug"]
-	diagnostics -> diagnostic_41 [label="Warning"]
-	diagnostics -> diagnostic_42 [label="Error"]
-	diagnostic_42 -> note_43 [label="note"]
-	diagnostics -> diagnostic_44 [label="Warning"]
-	diagnostics -> diagnostic_45 [label="Debug"]
-	diagnostics -> diagnostic_46 [label="Error"]
-	diagnostic_46 -> note_47 [label="note"]
-	diagnostics -> diagnostic_48 [label="Warning"]
+	diagnostics -> diagnostic_35 [label="Debug"]
+	diagnostics -> diagnostic_36 [label="Error"]
+	diagnostic_36 -> note_37 [label="note"]
+	diagnostics -> diagnostic_38 [label="Debug"]
+	diagnostics -> diagnostic_39 [label="Error"]
+	diagnostic_39 -> note_40 [label="note"]
 }

+ 16 - 8
tests/contract_testcases/solana/functions/selectors-must-be-different.sol

@@ -1,32 +1,40 @@
 abstract contract c {
-	function f1() selector=hex"01" public {}
+	@selector([1])
+	function f1() public {}
 	// error: selector must be unique
-	function f2() selector=hex"01" public {}
+	@selector([1])
+	function f2() public {}
 	// error: selector must be unique
-	function f3() selector=hex"01" public {}
+	@selector([1])
+	function f3() public {}
 }
 
 contract d {
 	int public c;
 
 	// error: selector is the same as c
-	function f1() selector=hex"13fbd725feff6e10" public {}
+	@selector([0x13, 0xfb, 0xd7, 0x25, 0xfe, 0xff, 0x6e, 0x10])
+	function f1() public {}
 }
 
 contract e {
 	// error: selector must be 8 bytes
-	function f1() selector=hex"01" public {}
+	@selector([1])
+	function f1() public {}
 }
 
 contract f {
 	// error: selectors are the same
-	function f1() selector=hex"41424344caffee00" public {}
-	function f2() selector=hex"41424344caffee00" public {}
+	@selector([0x41, 0x42, 0x43, 0x44, 0xca, 0xff, 0xee, 0x00])
+	function f1() public {}
+	@selector([0x41, 0x42, 0x43, 0x44, 0xca, 0xff, 0xee, 0x00])
+	function f2() public {}
 	function f3() public {}
 }
 
 contract g {
 	function f1() public {}
 	// error: selector for f3 matches f1
-	function f3() selector=hex"1b494cee9c541e94" public {}
+	@selector([0x1b, 0x49, 0x4c, 0xee, 0x9c, 0x54, 0x1e, 0x94])
+	function f3() public {}
 }

+ 58 - 0
tests/contract_testcases/solana/selector_override.dot

@@ -0,0 +1,58 @@
+strict digraph "tests/contract_testcases/solana/selector_override.sol" {
+	contract [label="contract selector\ntests/contract_testcases/solana/selector_override.sol:1:1-14:2"]
+	node_2 [label="constructor \ncontract: selector\ntests/contract_testcases/solana/selector_override.sol:3:2-16\nsignature ()\nvisibility public\nmutability nonpayable"]
+	m [label="modifier m\ncontract: selector\ntests/contract_testcases/solana/selector_override.sol:5:2-15\nmutability nonpayable"]
+	underscore [label="undersore\ntests/contract_testcases/solana/selector_override.sol:5:16-17"]
+	node_5 [label="receive \ncontract: selector\ntests/contract_testcases/solana/selector_override.sol:7:2-28\nmutability payable"]
+	node_6 [label="fallback \ncontract: selector\ntests/contract_testcases/solana/selector_override.sol:9:2-21\nmutability nonpayable"]
+	i [label="function i\ncontract: selector\ntests/contract_testcases/solana/selector_override.sol:11:2-23\nsignature i()\nvisibility internal\nmutability nonpayable"]
+	p [label="function p\ncontract: selector\ntests/contract_testcases/solana/selector_override.sol:13:2-22\nsignature p()\nvisibility private\nmutability nonpayable"]
+	contract_9 [label="contract TooLarge\ntests/contract_testcases/solana/selector_override.sol:16:1-26:2"]
+	get_foo [label="function get_foo\ncontract: TooLarge\ntests/contract_testcases/solana/selector_override.sol:18:5-49\nsignature get_foo()\nvisibility public\nmutability pure"]
+	returns [label="returns\nint256 "]
+	return [label="return\ntests/contract_testcases/solana/selector_override.sol:19:9-19"]
+	number_literal [label="int256 literal: 102\ntests/contract_testcases/solana/selector_override.sol:19:16-19"]
+	get_bar [label="function get_bar\ncontract: TooLarge\ntests/contract_testcases/solana/selector_override.sol:23:5-49\nsignature get_bar()\nvisibility public\nmutability pure"]
+	returns_15 [label="returns\nint256 "]
+	return_16 [label="return\ntests/contract_testcases/solana/selector_override.sol:24:9-19"]
+	number_literal_17 [label="int256 literal: 105\ntests/contract_testcases/solana/selector_override.sol:24:16-19"]
+	diagnostic [label="found contract 'selector'\nlevel Debug\ntests/contract_testcases/solana/selector_override.sol:1:1-14:2"]
+	diagnostic_20 [label="overriding selector not permitted on constructor\nlevel Error\ntests/contract_testcases/solana/selector_override.sol:2:2-25"]
+	diagnostic_21 [label="overriding selector not permitted on modifier\nlevel Error\ntests/contract_testcases/solana/selector_override.sol:4:2-16"]
+	diagnostic_22 [label="overriding selector not permitted on receive\nlevel Error\ntests/contract_testcases/solana/selector_override.sol:6:2-16"]
+	diagnostic_23 [label="target solana does not support receive() functions, see https://solang.readthedocs.io/en/latest/language/functions.html#fallback-and-receive-function\nlevel Error\ntests/contract_testcases/solana/selector_override.sol:7:2-28"]
+	diagnostic_24 [label="overriding selector not permitted on fallback\nlevel Error\ntests/contract_testcases/solana/selector_override.sol:8:2-20"]
+	diagnostic_25 [label="overriding selector only permitted on 'public' or 'external' function, not 'internal'\nlevel Error\ntests/contract_testcases/solana/selector_override.sol:10:2-25"]
+	diagnostic_26 [label="overriding selector only permitted on 'public' or 'external' function, not 'private'\nlevel Error\ntests/contract_testcases/solana/selector_override.sol:12:2-25"]
+	diagnostic_27 [label="found contract 'TooLarge'\nlevel Debug\ntests/contract_testcases/solana/selector_override.sol:16:1-26:2"]
+	diagnostic_28 [label="value 256 does not fit into type uint8.\nlevel Error\ntests/contract_testcases/solana/selector_override.sol:17:25-28"]
+	diagnostic_29 [label="value 2744 does not fit into type uint8.\nlevel Error\ntests/contract_testcases/solana/selector_override.sol:22:34-39"]
+	contracts -> contract
+	contract -> node_2 [label="constructor"]
+	contract -> m [label="modifier"]
+	m -> underscore [label="body"]
+	contract -> node_5 [label="receive"]
+	contract -> node_6 [label="fallback"]
+	contract -> i [label="function"]
+	contract -> p [label="function"]
+	contracts -> contract_9
+	contract_9 -> get_foo [label="function"]
+	get_foo -> returns [label="returns"]
+	get_foo -> return [label="body"]
+	return -> number_literal [label="expr"]
+	contract_9 -> get_bar [label="function"]
+	get_bar -> returns_15 [label="returns"]
+	get_bar -> return_16 [label="body"]
+	return_16 -> number_literal_17 [label="expr"]
+	diagnostics -> diagnostic [label="Debug"]
+	diagnostics -> diagnostic_20 [label="Error"]
+	diagnostics -> diagnostic_21 [label="Error"]
+	diagnostics -> diagnostic_22 [label="Error"]
+	diagnostics -> diagnostic_23 [label="Error"]
+	diagnostics -> diagnostic_24 [label="Error"]
+	diagnostics -> diagnostic_25 [label="Error"]
+	diagnostics -> diagnostic_26 [label="Error"]
+	diagnostics -> diagnostic_27 [label="Debug"]
+	diagnostics -> diagnostic_28 [label="Error"]
+	diagnostics -> diagnostic_29 [label="Error"]
+}

+ 80 - 0
tests/contract_testcases/solana/selectors-must-be-different.dot

@@ -0,0 +1,80 @@
+strict digraph "tests/contract_testcases/solana/selectors-must-be-different.sol" {
+	contract [label="contract c\ntests/contract_testcases/solana/selectors-must-be-different.sol:1:1-10:2"]
+	f1 [label="function f1\ncontract: c\ntests/contract_testcases/solana/selectors-must-be-different.sol:3:2-22\nsignature f1()\nvisibility public\nmutability nonpayable\nselector 01"]
+	f2 [label="function f2\ncontract: c\ntests/contract_testcases/solana/selectors-must-be-different.sol:6:2-22\nsignature f2()\nvisibility public\nmutability nonpayable\nselector 01"]
+	f3 [label="function f3\ncontract: c\ntests/contract_testcases/solana/selectors-must-be-different.sol:9:2-22\nsignature f3()\nvisibility public\nmutability nonpayable\nselector 01"]
+	contract_5 [label="contract d\ntests/contract_testcases/solana/selectors-must-be-different.sol:12:1-18:2"]
+	var [label="variable c\nvisibility public\ntests/contract_testcases/solana/selectors-must-be-different.sol:13:2-14"]
+	c [label="function c\ncontract: d\ntests/contract_testcases/solana/selectors-must-be-different.sol:13:13-14\nsignature c()\nvisibility public\nmutability view"]
+	returns [label="returns\nint256 "]
+	return [label="return\nimplicit"]
+	storage_load [label="storage load int256\nimplicit"]
+	storage_var [label="storage variable\nd.c\nint256 storage\nimplicit"]
+	f1_12 [label="function f1\ncontract: d\ntests/contract_testcases/solana/selectors-must-be-different.sol:17:2-22\nsignature f1()\nvisibility public\nmutability nonpayable\nselector c3da42b8"]
+	contract_13 [label="contract e\ntests/contract_testcases/solana/selectors-must-be-different.sol:20:1-24:2"]
+	f1_14 [label="function f1\ncontract: e\ntests/contract_testcases/solana/selectors-must-be-different.sol:23:2-22\nsignature f1()\nvisibility public\nmutability nonpayable\nselector 01"]
+	contract_15 [label="contract f\ntests/contract_testcases/solana/selectors-must-be-different.sol:26:1-33:2"]
+	f1_16 [label="function f1\ncontract: f\ntests/contract_testcases/solana/selectors-must-be-different.sol:29:2-22\nsignature f1()\nvisibility public\nmutability nonpayable\nselector 41424344"]
+	f2_17 [label="function f2\ncontract: f\ntests/contract_testcases/solana/selectors-must-be-different.sol:31:2-22\nsignature f2()\nvisibility public\nmutability nonpayable\nselector 41424344"]
+	f3_18 [label="function f3\ncontract: f\ntests/contract_testcases/solana/selectors-must-be-different.sol:32:2-22\nsignature f3()\nvisibility public\nmutability nonpayable"]
+	contract_19 [label="contract g\ntests/contract_testcases/solana/selectors-must-be-different.sol:35:1-40:2"]
+	f1_20 [label="function f1\ncontract: g\ntests/contract_testcases/solana/selectors-must-be-different.sol:36:2-22\nsignature f1()\nvisibility public\nmutability nonpayable"]
+	f3_21 [label="function f3\ncontract: g\ntests/contract_testcases/solana/selectors-must-be-different.sol:39:2-22\nsignature f3()\nvisibility public\nmutability nonpayable\nselector c27fc305"]
+	diagnostic [label="found abstract contract 'c'\nlevel Debug\ntests/contract_testcases/solana/selectors-must-be-different.sol:1:1-10:2"]
+	diagnostic_24 [label="function 'f2' selector is the same as function 'f1'\nlevel Error\ntests/contract_testcases/solana/selectors-must-be-different.sol:6:2-22"]
+	note [label="definition of function 'f1'\ntests/contract_testcases/solana/selectors-must-be-different.sol:3:2-22"]
+	diagnostic_26 [label="function 'f3' selector is the same as function 'f1'\nlevel Error\ntests/contract_testcases/solana/selectors-must-be-different.sol:9:2-22"]
+	note_27 [label="definition of function 'f1'\ntests/contract_testcases/solana/selectors-must-be-different.sol:3:2-22"]
+	diagnostic_28 [label="found contract 'd'\nlevel Debug\ntests/contract_testcases/solana/selectors-must-be-different.sol:12:1-18:2"]
+	diagnostic_29 [label="c is already defined as a contract name\nlevel Warning\ntests/contract_testcases/solana/selectors-must-be-different.sol:13:13-14"]
+	note_30 [label="location of previous definition\ntests/contract_testcases/solana/selectors-must-be-different.sol:1:1-10:2"]
+	diagnostic_31 [label="function 'f1' selector is the same as function 'c'\nlevel Error\ntests/contract_testcases/solana/selectors-must-be-different.sol:17:2-22"]
+	note_32 [label="definition of function 'c'\ntests/contract_testcases/solana/selectors-must-be-different.sol:13:13-14"]
+	diagnostic_33 [label="found contract 'e'\nlevel Debug\ntests/contract_testcases/solana/selectors-must-be-different.sol:20:1-24:2"]
+	diagnostic_34 [label="function 'f1' selector must be 4 bytes rather than 1 bytes\nlevel Error\ntests/contract_testcases/solana/selectors-must-be-different.sol:22:2-16"]
+	diagnostic_35 [label="found contract 'f'\nlevel Debug\ntests/contract_testcases/solana/selectors-must-be-different.sol:26:1-33:2"]
+	diagnostic_36 [label="function 'f2' selector is the same as function 'f1'\nlevel Error\ntests/contract_testcases/solana/selectors-must-be-different.sol:31:2-22"]
+	note_37 [label="definition of function 'f1'\ntests/contract_testcases/solana/selectors-must-be-different.sol:29:2-22"]
+	diagnostic_38 [label="found contract 'g'\nlevel Debug\ntests/contract_testcases/solana/selectors-must-be-different.sol:35:1-40:2"]
+	diagnostic_39 [label="function 'f3' selector is the same as function 'f1'\nlevel Error\ntests/contract_testcases/solana/selectors-must-be-different.sol:39:2-22"]
+	note_40 [label="definition of function 'f1'\ntests/contract_testcases/solana/selectors-must-be-different.sol:36:2-22"]
+	contracts -> contract
+	contract -> f1 [label="function"]
+	contract -> f2 [label="function"]
+	contract -> f3 [label="function"]
+	contracts -> contract_5
+	contract_5 -> var [label="variable"]
+	contract_5 -> c [label="function"]
+	c -> returns [label="returns"]
+	c -> return [label="body"]
+	return -> storage_load [label="expr"]
+	storage_load -> storage_var [label="expr"]
+	contract_5 -> f1_12 [label="function"]
+	contracts -> contract_13
+	contract_13 -> f1_14 [label="function"]
+	contracts -> contract_15
+	contract_15 -> f1_16 [label="function"]
+	contract_15 -> f2_17 [label="function"]
+	contract_15 -> f3_18 [label="function"]
+	contracts -> contract_19
+	contract_19 -> f1_20 [label="function"]
+	contract_19 -> f3_21 [label="function"]
+	diagnostics -> diagnostic [label="Debug"]
+	diagnostics -> diagnostic_24 [label="Error"]
+	diagnostic_24 -> note [label="note"]
+	diagnostics -> diagnostic_26 [label="Error"]
+	diagnostic_26 -> note_27 [label="note"]
+	diagnostics -> diagnostic_28 [label="Debug"]
+	diagnostics -> diagnostic_29 [label="Warning"]
+	diagnostic_29 -> note_30 [label="note"]
+	diagnostics -> diagnostic_31 [label="Error"]
+	diagnostic_31 -> note_32 [label="note"]
+	diagnostics -> diagnostic_33 [label="Debug"]
+	diagnostics -> diagnostic_34 [label="Error"]
+	diagnostics -> diagnostic_35 [label="Debug"]
+	diagnostics -> diagnostic_36 [label="Error"]
+	diagnostic_36 -> note_37 [label="note"]
+	diagnostics -> diagnostic_38 [label="Debug"]
+	diagnostics -> diagnostic_39 [label="Error"]
+	diagnostic_39 -> note_40 [label="note"]
+}

+ 19 - 17
tests/contract_testcases/substrate/selector_override.dot

@@ -1,30 +1,32 @@
 strict digraph "tests/contract_testcases/substrate/selector_override.sol" {
-	contract [label="contract selector\ntests/contract_testcases/substrate/selector_override.sol:1:1-8:2"]
-	m [label="modifier m\ncontract: selector\ntests/contract_testcases/substrate/selector_override.sol:3:2-29\nmutability nonpayable"]
-	underscore [label="undersore\ntests/contract_testcases/substrate/selector_override.sol:3:31-32"]
-	node_4 [label="receive \ncontract: selector\ntests/contract_testcases/substrate/selector_override.sol:4:2-44\nmutability payable"]
-	node_5 [label="fallback \ncontract: selector\ntests/contract_testcases/substrate/selector_override.sol:5:2-39\nmutability nonpayable"]
-	i [label="function i\ncontract: selector\ntests/contract_testcases/substrate/selector_override.sol:6:2-45\nsignature i()\nvisibility internal\nmutability nonpayable"]
-	p [label="function p\ncontract: selector\ntests/contract_testcases/substrate/selector_override.sol:7:2-44\nsignature p()\nvisibility private\nmutability nonpayable"]
-	diagnostic [label="found contract 'selector'\nlevel Debug\ntests/contract_testcases/substrate/selector_override.sol:1:1-8:2"]
-	diagnostic_10 [label="selector is 2 bytes, 4 bytes expected\nlevel Error\ntests/contract_testcases/substrate/selector_override.sol:2:25-34"]
-	diagnostic_11 [label="overriding selector not permitted on modifier\nlevel Error\ntests/contract_testcases/substrate/selector_override.sol:3:24-29"]
-	diagnostic_12 [label="overriding selector not permitted on receive\nlevel Error\ntests/contract_testcases/substrate/selector_override.sol:4:38-44"]
-	diagnostic_13 [label="overriding selector not permitted on fallback\nlevel Error\ntests/contract_testcases/substrate/selector_override.sol:5:31-39"]
-	diagnostic_14 [label="overriding selector only permitted on 'public' or 'external' function, not 'internal'\nlevel Error\ntests/contract_testcases/substrate/selector_override.sol:6:35-45"]
-	diagnostic_15 [label="overriding selector only permitted on 'public' or 'external' function, not 'private'\nlevel Error\ntests/contract_testcases/substrate/selector_override.sol:7:34-44"]
+	contract [label="contract selector\ntests/contract_testcases/substrate/selector_override.sol:1:1-14:2"]
+	new [label="constructor new\ncontract: selector\ntests/contract_testcases/substrate/selector_override.sol:3:2-16\nsignature new()\nvisibility public\nmutability nonpayable\nselector abcd"]
+	m [label="modifier m\ncontract: selector\ntests/contract_testcases/substrate/selector_override.sol:5:2-15\nmutability nonpayable"]
+	underscore [label="undersore\ntests/contract_testcases/substrate/selector_override.sol:5:16-17"]
+	node_5 [label="receive \ncontract: selector\ntests/contract_testcases/substrate/selector_override.sol:7:2-28\nmutability payable"]
+	node_6 [label="fallback \ncontract: selector\ntests/contract_testcases/substrate/selector_override.sol:9:2-21\nmutability nonpayable"]
+	i [label="function i\ncontract: selector\ntests/contract_testcases/substrate/selector_override.sol:11:2-23\nsignature i()\nvisibility internal\nmutability nonpayable"]
+	p [label="function p\ncontract: selector\ntests/contract_testcases/substrate/selector_override.sol:13:2-22\nsignature p()\nvisibility private\nmutability nonpayable"]
+	diagnostic [label="found contract 'selector'\nlevel Debug\ntests/contract_testcases/substrate/selector_override.sol:1:1-14:2"]
+	diagnostic_11 [label="function 'new' selector must be 4 bytes rather than 2 bytes\nlevel Error\ntests/contract_testcases/substrate/selector_override.sol:2:2-25"]
+	diagnostic_12 [label="overriding selector not permitted on modifier\nlevel Error\ntests/contract_testcases/substrate/selector_override.sol:4:2-16"]
+	diagnostic_13 [label="overriding selector not permitted on receive\nlevel Error\ntests/contract_testcases/substrate/selector_override.sol:6:2-16"]
+	diagnostic_14 [label="overriding selector not permitted on fallback\nlevel Error\ntests/contract_testcases/substrate/selector_override.sol:8:2-20"]
+	diagnostic_15 [label="overriding selector only permitted on 'public' or 'external' function, not 'internal'\nlevel Error\ntests/contract_testcases/substrate/selector_override.sol:10:2-25"]
+	diagnostic_16 [label="overriding selector only permitted on 'public' or 'external' function, not 'private'\nlevel Error\ntests/contract_testcases/substrate/selector_override.sol:12:2-25"]
 	contracts -> contract
+	contract -> new [label="constructor"]
 	contract -> m [label="modifier"]
 	m -> underscore [label="body"]
-	contract -> node_4 [label="receive"]
-	contract -> node_5 [label="fallback"]
+	contract -> node_5 [label="receive"]
+	contract -> node_6 [label="fallback"]
 	contract -> i [label="function"]
 	contract -> p [label="function"]
 	diagnostics -> diagnostic [label="Debug"]
-	diagnostics -> diagnostic_10 [label="Error"]
 	diagnostics -> diagnostic_11 [label="Error"]
 	diagnostics -> diagnostic_12 [label="Error"]
 	diagnostics -> diagnostic_13 [label="Error"]
 	diagnostics -> diagnostic_14 [label="Error"]
 	diagnostics -> diagnostic_15 [label="Error"]
+	diagnostics -> diagnostic_16 [label="Error"]
 }

+ 12 - 6
tests/contract_testcases/substrate/selector_override.sol

@@ -1,8 +1,14 @@
 contract selector {
-	constructor() selector=hex"abcd" {}
-	modifier m() selector=hex"" {_;}
-	receive() payable external selector=hex"1" {}
-	fallback() external selector=hex"abc" {}
-	function i() internal selector = hex"ab_dd" {}
-	function p() private selector = hex"ab_dd" {}
+	@selector([0xab, 0xcd])
+	constructor() {}
+	@selector([x])
+	modifier m() {_;}
+	@selector([1])
+	receive() payable external {}
+	@selector([0xabc])
+	fallback() external {}
+	@selector([0xab, 0xdd])
+	function i() internal {}
+	@selector([0xab, 0xdd])
+	function p() private {}
 }

+ 24 - 24
tests/contract_testcases/substrate/selector_override_inherited.dot

@@ -1,28 +1,28 @@
 strict digraph "tests/contract_testcases/substrate/selector_override_inherited.sol" {
-	contract [label="contract base\ntests/contract_testcases/substrate/selector_override_inherited.sol:1:1-3:2"]
-	func [label="function func\ncontract: base\ntests/contract_testcases/substrate/selector_override_inherited.sol:2:2-55\nsignature func()\nvisibility public\nmutability nonpayable\nvirtual\nselector abcdef01"]
-	contract_3 [label="contract child\ntests/contract_testcases/substrate/selector_override_inherited.sol:5:1-7:2"]
-	base [label="base base\ntests/contract_testcases/substrate/selector_override_inherited.sol:5:19-23"]
-	func_5 [label="function func\ncontract: child\ntests/contract_testcases/substrate/selector_override_inherited.sol:6:2-56\nsignature func()\nvisibility public\nmutability nonpayable\noverride\nselector abcdef02"]
-	contract_6 [label="contract child2\ntests/contract_testcases/substrate/selector_override_inherited.sol:9:1-11:2"]
-	base_7 [label="base base\ntests/contract_testcases/substrate/selector_override_inherited.sol:9:20-24"]
-	func_8 [label="function func\ncontract: child2\ntests/contract_testcases/substrate/selector_override_inherited.sol:10:2-33\nsignature func()\nvisibility public\nmutability nonpayable\noverride"]
-	contract_9 [label="contract base2\ntests/contract_testcases/substrate/selector_override_inherited.sol:13:1-15:2"]
-	func_10 [label="function func\ncontract: base2\ntests/contract_testcases/substrate/selector_override_inherited.sol:14:2-32\nsignature func()\nvisibility public\nmutability nonpayable\nvirtual"]
-	contract_11 [label="contract child3\ntests/contract_testcases/substrate/selector_override_inherited.sol:17:1-19:2"]
-	base_12 [label="base base2\ntests/contract_testcases/substrate/selector_override_inherited.sol:17:20-25"]
-	func_13 [label="function func\ncontract: child3\ntests/contract_testcases/substrate/selector_override_inherited.sol:18:2-56\nsignature func()\nvisibility public\nmutability nonpayable\noverride\nselector abcdef02"]
-	diagnostic [label="found contract 'base'\nlevel Debug\ntests/contract_testcases/substrate/selector_override_inherited.sol:1:1-3:2"]
-	diagnostic_16 [label="found contract 'child'\nlevel Debug\ntests/contract_testcases/substrate/selector_override_inherited.sol:5:1-7:2"]
-	diagnostic_17 [label="selector 'abcdef02' of function 'func' different from base selector 'abcdef01'\nlevel Error\ntests/contract_testcases/substrate/selector_override_inherited.sol:6:2-56"]
-	note [label="location of base function\ntests/contract_testcases/substrate/selector_override_inherited.sol:2:2-55"]
-	diagnostic_19 [label="found contract 'child2'\nlevel Debug\ntests/contract_testcases/substrate/selector_override_inherited.sol:9:1-11:2"]
-	diagnostic_20 [label="selector of function 'func' must match base selector 'abcdef01'\nlevel Error\ntests/contract_testcases/substrate/selector_override_inherited.sol:10:2-33"]
-	note_21 [label="location of base function\ntests/contract_testcases/substrate/selector_override_inherited.sol:2:2-55"]
-	diagnostic_22 [label="found contract 'base2'\nlevel Debug\ntests/contract_testcases/substrate/selector_override_inherited.sol:13:1-15:2"]
-	diagnostic_23 [label="found contract 'child3'\nlevel Debug\ntests/contract_testcases/substrate/selector_override_inherited.sol:17:1-19:2"]
-	diagnostic_24 [label="base function needs same selector as selector 'abcdef02' of function 'func'\nlevel Error\ntests/contract_testcases/substrate/selector_override_inherited.sol:18:2-56"]
-	note_25 [label="location of base function\ntests/contract_testcases/substrate/selector_override_inherited.sol:14:2-32"]
+	contract [label="contract base\ntests/contract_testcases/substrate/selector_override_inherited.sol:1:1-4:2"]
+	func [label="function func\ncontract: base\ntests/contract_testcases/substrate/selector_override_inherited.sol:3:2-32\nsignature func()\nvisibility public\nmutability nonpayable\nvirtual\nselector abcdef01"]
+	contract_3 [label="contract child\ntests/contract_testcases/substrate/selector_override_inherited.sol:6:1-9:2"]
+	base [label="base base\ntests/contract_testcases/substrate/selector_override_inherited.sol:6:19-23"]
+	func_5 [label="function func\ncontract: child\ntests/contract_testcases/substrate/selector_override_inherited.sol:8:2-33\nsignature func()\nvisibility public\nmutability nonpayable\noverride\nselector abcdef02"]
+	contract_6 [label="contract child2\ntests/contract_testcases/substrate/selector_override_inherited.sol:11:1-13:2"]
+	base_7 [label="base base\ntests/contract_testcases/substrate/selector_override_inherited.sol:11:20-24"]
+	func_8 [label="function func\ncontract: child2\ntests/contract_testcases/substrate/selector_override_inherited.sol:12:2-33\nsignature func()\nvisibility public\nmutability nonpayable\noverride"]
+	contract_9 [label="contract base2\ntests/contract_testcases/substrate/selector_override_inherited.sol:15:1-17:2"]
+	func_10 [label="function func\ncontract: base2\ntests/contract_testcases/substrate/selector_override_inherited.sol:16:2-32\nsignature func()\nvisibility public\nmutability nonpayable\nvirtual"]
+	contract_11 [label="contract child3\ntests/contract_testcases/substrate/selector_override_inherited.sol:19:1-22:2"]
+	base_12 [label="base base2\ntests/contract_testcases/substrate/selector_override_inherited.sol:19:20-25"]
+	func_13 [label="function func\ncontract: child3\ntests/contract_testcases/substrate/selector_override_inherited.sol:21:2-33\nsignature func()\nvisibility public\nmutability nonpayable\noverride\nselector abcdef02"]
+	diagnostic [label="found contract 'base'\nlevel Debug\ntests/contract_testcases/substrate/selector_override_inherited.sol:1:1-4:2"]
+	diagnostic_16 [label="found contract 'child'\nlevel Debug\ntests/contract_testcases/substrate/selector_override_inherited.sol:6:1-9:2"]
+	diagnostic_17 [label="selector of function 'func' different from base selector\nlevel Error\ntests/contract_testcases/substrate/selector_override_inherited.sol:7:2-37"]
+	note [label="location of base function\ntests/contract_testcases/substrate/selector_override_inherited.sol:2:2-37"]
+	diagnostic_19 [label="found contract 'child2'\nlevel Debug\ntests/contract_testcases/substrate/selector_override_inherited.sol:11:1-13:2"]
+	diagnostic_20 [label="selector of function 'func' must match base selector\nlevel Error\ntests/contract_testcases/substrate/selector_override_inherited.sol:12:2-33"]
+	note_21 [label="location of base function\ntests/contract_testcases/substrate/selector_override_inherited.sol:2:2-37"]
+	diagnostic_22 [label="found contract 'base2'\nlevel Debug\ntests/contract_testcases/substrate/selector_override_inherited.sol:15:1-17:2"]
+	diagnostic_23 [label="found contract 'child3'\nlevel Debug\ntests/contract_testcases/substrate/selector_override_inherited.sol:19:1-22:2"]
+	diagnostic_24 [label="base function needs same selector as selector of function 'func'\nlevel Error\ntests/contract_testcases/substrate/selector_override_inherited.sol:20:2-37"]
+	note_25 [label="location of base function\ntests/contract_testcases/substrate/selector_override_inherited.sol:16:2-32"]
 	contracts -> contract
 	contract -> func [label="function"]
 	contracts -> contract_3

+ 7 - 6
tests/contract_testcases/substrate/selector_override_inherited.sol

@@ -1,9 +1,11 @@
 contract base {
-	function func() selector=hex"abcdef01" public virtual {}
+	@selector([0xab, 0xcd, 0xef, 0x01])
+	function func() public virtual {}
 }
 
 contract child is base {
-	function func() selector=hex"abcdef02" public override {}
+	@selector([0xab, 0xcd, 0xef, 0x02])
+	function func() public override {}
 }
 
 contract child2 is base {
@@ -15,7 +17,6 @@ contract base2 {
 }
 
 contract child3 is base2 {
-	function func() selector=hex"abcdef02" public override {}
-}
-
-
+	@selector([0xab, 0xcd, 0xef, 0x02])
+	function func() public override {}
+}

+ 2 - 1
tests/doc_examples.rs

@@ -31,7 +31,8 @@ fn file_resolver(target: Target) -> FileResolver {
                 r##"
                 anchor_anchor constant bobcat = anchor_anchor(address'z7FbDfQDfucxJz5o8jrGLgvSbdoeSqX5VrxBb5TVjHq');
                 interface anchor_anchor {
-                    function pounce() selector=hex"afaf6d1f0d989bed" view external returns(int64);
+                    @selector([0xaf, 0xaf, 0x6d, 0x1f, 0x0d, 0x98, 0x9b, 0xed])
+                    function pounce() view external returns(int64);
                 }"##.into(),
             );
     }

+ 4 - 2
tests/substrate_tests/functions.rs

@@ -80,7 +80,8 @@ fn constructor_override_selector() {
         contract test {
             uint64 result;
 
-            constructor(uint64 x) selector=hex"01020304" {
+            @selector([1, 2, 3, 4])
+            constructor(uint64 x) {
                 result = x;
             }
 
@@ -110,7 +111,8 @@ fn function_override_selector() {
                 result = 1;
             }
 
-            function set(uint64 x) selector=hex"01020304" public {
+            @selector([1, 2, 3, 4])
+            function set(uint64 x) public {
                 result = x;
             }