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 years ago
parent
commit
bd65c96b44
31 changed files with 593 additions and 368 deletions
  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/)
 All notable changes to [Solang](https://github.com/hyperledger/solang/)
 will be documented here.
 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
 ## 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
 ### Added
 - **Solana / breaking:** The try-catch construct is no longer permitted on Solana, as it
 - **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
 - **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
   a Solidity interface file from an Anchor IDL file. This can be used for calling
   Anchor Contracts on Solana. [seanyoung](https://github.com/seanyoung)
   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)
   [xermicus](https://github.com/xermicus)
 
 
 ### Changed
 ### 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`.
 - **Substrate / breaking:** Supported node version is now pallet contracts `v0.22.1`.
   [xermicus](https://github.com/xermicus)
   [xermicus](https://github.com/xermicus)
 - **Substrate / breaking:** Remove the deprecated `random` builtin.
 - **Substrate / breaking:** Remove the deprecated `random` builtin.
   [xermicus](https://github.com/xermicus)
   [xermicus](https://github.com/xermicus)
 
 
 ### Fixed
 ### 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).
 - **Substrate / breaking:** Solang is now compatible with `ink!` version 4 (beta).
   [xermicus](https://github.com/xermicus)
   [xermicus](https://github.com/xermicus)
 - **Substrate:** Switched ABI generation to use official `ink!` crates, which fixes all
 - **Substrate:** Switched ABI generation to use official `ink!` crates, which fixes all
   remaining metadata regressions.
   remaining metadata regressions.
   [extraymond](https://github.com/extraymond) and [xermicus](https://github.com/xermicus)
   [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!`.
   supported, like in `ink!`.
   [xermicus](https://github.com/xermicus)
   [xermicus](https://github.com/xermicus)
 - All provided examples as well as most of the Solidity code snippets in our
 - 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 {
 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;
         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
 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.
 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
 .. include:: ../examples/substrate/function_selector_override.sol
   :code: solidity
   :code: solidity

+ 2 - 1
integration/substrate/inkee.sol

@@ -1,5 +1,6 @@
 contract Inkee {
 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;
         return v;
     }
     }
 }
 }

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

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

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

@@ -579,9 +579,6 @@ FunctionAttribute: FunctionAttribute = {
         FunctionAttribute::Override(Loc::File(file_no, l, r), list)
         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> <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> => {
     <l:@L> <false_token:!> <r:@R> => {
         parser_errors.push(false_token);
         parser_errors.push(false_token);
         FunctionAttribute::Error(Loc::File(file_no, l ,r))
         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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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![] }
                 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 anchor_syn::idl::{Idl, IdlInstruction, IdlType, IdlTypeDefinitionTy};
 use clap::ArgMatches;
 use clap::ArgMatches;
+use itertools::Itertools;
 use serde_json::Value as JsonValue;
 use serde_json::Value as JsonValue;
 use solang::abi::anchor::discriminator;
 use solang::abi::anchor::discriminator;
 use solang_parser::lexer::is_keyword;
 use solang_parser::lexer::is_keyword;
@@ -280,9 +281,13 @@ fn instruction(
             .unwrap()
             .unwrap()
             .1;
             .1;
 
 
+        // The anchor discriminator is what Solidity calls a selector
+        let selector = discriminator(if state { "state" } else { "global" }, &instr.name);
+
         write!(
         write!(
             f,
             f,
-            "\tfunction {}(",
+            "\t@selector([{}])\n\tfunction {}(",
+            selector.iter().map(|v| format!("{:#04x}", v)).join(","),
             if instr.name == "new" {
             if instr.name == "new" {
                 "initialize"
                 "initialize"
             } else {
             } 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 {
         if let Some(ty) = &instr.returns {
             writeln!(
             writeln!(

+ 2 - 2
src/sema/ast.rs

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

+ 23 - 19
src/sema/contracts.rs

@@ -827,14 +827,12 @@ fn base_function_compatible(
         (cur, func) if cur == func => (),
         (cur, func) if cur == func => (),
         (Some(cur_selector), Some(func_selector)) => {
         (Some(cur_selector), Some(func_selector)) => {
             diagnostics.push(ast::Diagnostic::error_with_note(
             diagnostics.push(ast::Diagnostic::error_with_note(
-                func.loc,
+                cur_selector.0,
                 format!(
                 format!(
-                    "selector '{}' of function '{}' different from base selector '{}'",
-                    hex::encode(cur_selector),
+                    "selector of function '{}' different from base selector",
                     func.name,
                     func.name,
-                    hex::encode(func_selector)
                 ),
                 ),
-                base.loc,
+                func_selector.0,
                 String::from("location of base function"),
                 String::from("location of base function"),
             ));
             ));
         }
         }
@@ -842,20 +840,18 @@ fn base_function_compatible(
             diagnostics.push(ast::Diagnostic::error_with_note(
             diagnostics.push(ast::Diagnostic::error_with_note(
                 func.loc,
                 func.loc,
                 format!(
                 format!(
-                    "selector of function '{}' must match base selector '{}'",
+                    "selector of function '{}' must match base selector",
                     func.name,
                     func.name,
-                    hex::encode(func_selector)
                 ),
                 ),
-                base.loc,
+                func_selector.0,
                 String::from("location of base function"),
                 String::from("location of base function"),
             ));
             ));
         }
         }
         (Some(cur_selector), None) => {
         (Some(cur_selector), None) => {
             diagnostics.push(ast::Diagnostic::error_with_note(
             diagnostics.push(ast::Diagnostic::error_with_note(
-                func.loc,
+                cur_selector.0,
                 format!(
                 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,
                     func.name,
                 ),
                 ),
                 base.loc,
                 base.loc,
@@ -909,9 +905,14 @@ fn resolve_declarations<'a>(
     // resolve function signatures
     // resolve function signatures
     for part in &def.parts {
     for part in &def.parts {
         if let pt::ContractPart::FunctionDefinition(ref f) = &part.part {
         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() {
                 if f.body.is_some() {
                     delayed.function_bodies.push(DelayedResolveFunction {
                     delayed.function_bodies.push(DelayedResolveFunction {
                         contract_no: def.contract_no,
                         contract_no: def.contract_no,
@@ -920,8 +921,6 @@ fn resolve_declarations<'a>(
                         annotations: part.annotations.clone(),
                         annotations: part.annotations.clone(),
                     });
                     });
                 } else {
                 } else {
-                    annotions_not_allowed(&part.annotations, &format!("{} with no body", f.ty), ns);
-
                     function_no_bodies.push(function_no);
                     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
         // On Solana, concrete contracts have selectors of 8 bytes
         if ns.contracts[contract_no].is_concrete() && selector.len() != selector_len as usize {
         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(
             diagnostics.push(ast::Diagnostic::error(
-                func.loc,
+                *loc,
                 format!(
                 format!(
-                    "function '{}' selector '{}' must be {} bytes rather than {} bytes",
+                    "function '{}' selector must be {} bytes rather than {} bytes",
                     func.name,
                     func.name,
-                    hex::encode(&selector),
                     selector_len,
                     selector_len,
                     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)));
             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.
 /// 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 let Type::Uint(bits) = ty {
         // If the result sign is minus, throw an error.
         // If the result sign is minus, throw an error.
         if let Sign::Minus = result.sign() {
         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
 /// Resolve the given number literal, multiplied by value of unit
-fn number_literal(
+pub(super) fn number_literal(
     loc: &pt::Loc,
     loc: &pt::Loc,
     integer: &str,
     integer: &str,
     exp: &str,
     exp: &str,
@@ -2502,7 +2502,7 @@ fn hex_literal(
     }
     }
 }
 }
 
 
-fn hex_number_literal(
+pub(super) fn hex_number_literal(
     loc: &pt::Loc,
     loc: &pt::Loc,
     n: &str,
     n: &str,
     ns: &mut Namespace,
     ns: &mut Namespace,

+ 136 - 3
src/sema/function_annotation.rs

@@ -1,18 +1,147 @@
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 use super::{
 use super::{
-    ast::{ConstructorAnnotation, Diagnostic, Namespace, Type},
+    ast::{ConstructorAnnotation, Diagnostic, Expression, Function, Namespace, Type},
     diagnostics::Diagnostics,
     diagnostics::Diagnostics,
-    expression::{expression, ExprContext, ResolveTo},
+    eval::overflow_check,
+    expression::{expression, hex_number_literal, number_literal, ExprContext, ResolveTo},
     unused_variable::used_variable,
     unused_variable::used_variable,
     Symtable,
     Symtable,
 };
 };
 use crate::Target;
 use crate::Target;
+use num_bigint::BigInt;
+use num_traits::{One, ToPrimitive};
 use solang_parser::pt::{self, CodeLocation};
 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
 /// 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.
 /// 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,
     function_no: usize,
     annotations: &[&pt::Annotation],
     annotations: &[&pt::Annotation],
     symtable: &mut Symtable,
     symtable: &mut Symtable,
@@ -38,6 +167,10 @@ pub fn function_annotations(
 
 
     for note in annotations {
     for note in annotations {
         match note.id.name.as_str() {
         match note.id.name.as_str() {
+            "selector" => {
+                // selectors already done in function_prototype_annotations
+                // without using a symbol table
+            }
             "seed" if is_solana_constructor => {
             "seed" if is_solana_constructor => {
                 let ty = Type::Slice(Box::new(Type::Bytes(1)));
                 let ty = Type::Slice(Box::new(Type::Bytes(1)));
                 let loc = note.loc;
                 let loc = note.loc;

+ 6 - 111
src/sema/functions.rs

@@ -1,15 +1,12 @@
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: Apache-2.0
 
 
 use super::{
 use super::{
-    ast::{
-        Diagnostic, Expression, Function, Mutability, Namespace, Parameter, StructType, Symbol,
-        Type,
-    },
+    ast::{Diagnostic, Function, Mutability, Namespace, Parameter, StructType, Symbol, Type},
     contracts::is_base,
     contracts::is_base,
     diagnostics::Diagnostics,
     diagnostics::Diagnostics,
-    expression::{expression, ExprContext, ResolveTo},
+    function_annotation::function_prototype_annotations,
     tags::resolve_tags,
     tags::resolve_tags,
-    ContractDefinition, Symtable,
+    ContractDefinition,
 };
 };
 use crate::Target;
 use crate::Target;
 use solang_parser::{
 use solang_parser::{
@@ -23,6 +20,7 @@ pub fn contract_function(
     contract: &ContractDefinition,
     contract: &ContractDefinition,
     func: &pt::FunctionDefinition,
     func: &pt::FunctionDefinition,
     tags: &[DocComment],
     tags: &[DocComment],
+    annotations: &[&pt::Annotation],
     file_no: usize,
     file_no: usize,
     ns: &mut Namespace,
     ns: &mut Namespace,
 ) -> Option<usize> {
 ) -> Option<usize> {
@@ -113,7 +111,6 @@ pub fn contract_function(
     let mut visibility: Option<pt::Visibility> = None;
     let mut visibility: Option<pt::Visibility> = None;
     let mut is_virtual: Option<pt::Loc> = None;
     let mut is_virtual: Option<pt::Loc> = None;
     let mut is_override: Option<(pt::Loc, Vec<usize>)> = None;
     let mut is_override: Option<(pt::Loc, Vec<usize>)> = None;
-    let mut has_selector: Option<&pt::Expression> = None;
 
 
     for a in &func.attributes {
     for a in &func.attributes {
         match &a {
         match &a {
@@ -176,34 +173,6 @@ pub fn contract_function(
 
 
                 is_virtual = Some(*loc);
                 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) => {
             pt::FunctionAttribute::Override(loc, bases) => {
                 if let Some((prev_loc, _)) = &is_override {
                 if let Some((prev_loc, _)) = &is_override {
                     ns.diagnostics.push(Diagnostic::error_with_note(
                     ns.diagnostics.push(Diagnostic::error_with_note(
@@ -334,74 +303,6 @@ pub fn contract_function(
 
 
     let mut diagnostics = Diagnostics::default();
     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(
     let (params, params_success) = resolve_params(
         &func.params,
         &func.params,
         storage_allowed,
         storage_allowed,
@@ -567,7 +468,8 @@ pub fn contract_function(
     fdecl.is_virtual = is_virtual;
     fdecl.is_virtual = is_virtual;
     fdecl.is_override = is_override;
     fdecl.is_override = is_override;
     fdecl.has_body = func.body.is_some();
     fdecl.has_body = func.body.is_some();
-    fdecl.selector = selector;
+
+    function_prototype_annotations(&mut fdecl, annotations, ns);
 
 
     if func.ty == pt::FunctionTy::Constructor {
     if func.ty == pt::FunctionTy::Constructor {
         // In the eth solidity only one constructor is allowed
         // In the eth solidity only one constructor is allowed
@@ -827,13 +729,6 @@ pub fn function(
                 ));
                 ));
                 success = false;
                 success = false;
             }
             }
-            pt::FunctionAttribute::NameValue(loc, name, _) => {
-                ns.diagnostics.push(Diagnostic::error(
-                    *loc,
-                    format!("attribute '{}' not supported", name.name),
-                ));
-                success = false;
-            }
             pt::FunctionAttribute::Error(_) => {
             pt::FunctionAttribute::Error(_) => {
                 success = false;
                 success = false;
             }
             }

+ 2 - 2
src/sema/statements.rs

@@ -11,7 +11,7 @@ use super::expression::{
 };
 };
 use super::symtable::{LoopScopes, Symtable};
 use super::symtable::{LoopScopes, Symtable};
 use crate::sema::builtin;
 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::symtable::{VariableInitializer, VariableUsage};
 use crate::sema::unused_variable::{assigned_variable, check_function_call, used_variable};
 use crate::sema::unused_variable::{assigned_variable, check_function_call, used_variable};
 use crate::sema::yul::resolve_inline_assembly;
 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
     // now that the function arguments have been resolved, we can resolve the bases for
     // constructors.
     // constructors.

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

@@ -1,19 +1,19 @@
 strict digraph "tests/contract_testcases/evm/selector_override.sol" {
 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
 	contracts -> contract
 	contract -> node_2 [label="constructor"]
 	contract -> node_2 [label="constructor"]
 	contract -> m [label="modifier"]
 	contract -> m [label="modifier"]

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

@@ -1,8 +1,14 @@
 contract selector {
 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_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_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_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 -> EB
 	enums -> e
 	enums -> e
 	enums -> f
 	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" {
 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
 	contracts -> contract
 	contract -> node_2 [label="constructor"]
 	contract -> node_2 [label="constructor"]
 	contract -> m [label="modifier"]
 	contract -> m [label="modifier"]
@@ -29,18 +35,24 @@ strict digraph "tests/contract_testcases/solana/functions/selector_override.sol"
 	contract -> node_6 [label="fallback"]
 	contract -> node_6 [label="fallback"]
 	contract -> i [label="function"]
 	contract -> i [label="function"]
 	contract -> p [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 [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_21 [label="Error"]
-	diagnostics -> diagnostic_22 [label="Warning"]
+	diagnostics -> diagnostic_22 [label="Error"]
 	diagnostics -> diagnostic_23 [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 {
 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" {
 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 "]
 	returns [label="returns\nint256 "]
 	return [label="return\nimplicit"]
 	return [label="return\nimplicit"]
 	storage_load [label="storage load int256\nimplicit"]
 	storage_load [label="storage load int256\nimplicit"]
 	storage_var [label="storage variable\nd.c\nint256 storage\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
 	contracts -> contract
 	contract -> f1 [label="function"]
 	contract -> f1 [label="function"]
 	contract -> f2 [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 -> f1_20 [label="function"]
 	contract_19 -> f3_21 [label="function"]
 	contract_19 -> f3_21 [label="function"]
 	diagnostics -> diagnostic [label="Debug"]
 	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"]
 	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 {
 abstract contract c {
-	function f1() selector=hex"01" public {}
+	@selector([1])
+	function f1() public {}
 	// error: selector must be unique
 	// error: selector must be unique
-	function f2() selector=hex"01" public {}
+	@selector([1])
+	function f2() public {}
 	// error: selector must be unique
 	// error: selector must be unique
-	function f3() selector=hex"01" public {}
+	@selector([1])
+	function f3() public {}
 }
 }
 
 
 contract d {
 contract d {
 	int public c;
 	int public c;
 
 
 	// error: selector is the same as 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 {
 contract e {
 	// error: selector must be 8 bytes
 	// error: selector must be 8 bytes
-	function f1() selector=hex"01" public {}
+	@selector([1])
+	function f1() public {}
 }
 }
 
 
 contract f {
 contract f {
 	// error: selectors are the same
 	// 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 {}
 	function f3() public {}
 }
 }
 
 
 contract g {
 contract g {
 	function f1() public {}
 	function f1() public {}
 	// error: selector for f3 matches f1
 	// 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" {
 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
 	contracts -> contract
+	contract -> new [label="constructor"]
 	contract -> m [label="modifier"]
 	contract -> m [label="modifier"]
 	m -> underscore [label="body"]
 	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 -> i [label="function"]
 	contract -> p [label="function"]
 	contract -> p [label="function"]
 	diagnostics -> diagnostic [label="Debug"]
 	diagnostics -> diagnostic [label="Debug"]
-	diagnostics -> diagnostic_10 [label="Error"]
 	diagnostics -> diagnostic_11 [label="Error"]
 	diagnostics -> diagnostic_11 [label="Error"]
 	diagnostics -> diagnostic_12 [label="Error"]
 	diagnostics -> diagnostic_12 [label="Error"]
 	diagnostics -> diagnostic_13 [label="Error"]
 	diagnostics -> diagnostic_13 [label="Error"]
 	diagnostics -> diagnostic_14 [label="Error"]
 	diagnostics -> diagnostic_14 [label="Error"]
 	diagnostics -> diagnostic_15 [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 {
 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" {
 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
 	contracts -> contract
 	contract -> func [label="function"]
 	contract -> func [label="function"]
 	contracts -> contract_3
 	contracts -> contract_3

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

@@ -1,9 +1,11 @@
 contract base {
 contract base {
-	function func() selector=hex"abcdef01" public virtual {}
+	@selector([0xab, 0xcd, 0xef, 0x01])
+	function func() public virtual {}
 }
 }
 
 
 contract child is base {
 contract child is base {
-	function func() selector=hex"abcdef02" public override {}
+	@selector([0xab, 0xcd, 0xef, 0x02])
+	function func() public override {}
 }
 }
 
 
 contract child2 is base {
 contract child2 is base {
@@ -15,7 +17,6 @@ contract base2 {
 }
 }
 
 
 contract child3 is 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##"
                 r##"
                 anchor_anchor constant bobcat = anchor_anchor(address'z7FbDfQDfucxJz5o8jrGLgvSbdoeSqX5VrxBb5TVjHq');
                 anchor_anchor constant bobcat = anchor_anchor(address'z7FbDfQDfucxJz5o8jrGLgvSbdoeSqX5VrxBb5TVjHq');
                 interface anchor_anchor {
                 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(),
                 }"##.into(),
             );
             );
     }
     }

+ 4 - 2
tests/substrate_tests/functions.rs

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