mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Allow event definitions at file level
This commit is contained in:
parent
020b59680e
commit
b0a986ffff
@ -1,6 +1,7 @@
|
||||
### 0.8.22 (unreleased)
|
||||
|
||||
Language Features:
|
||||
* Allow defining events at file level.
|
||||
|
||||
|
||||
Compiler Features:
|
||||
|
@ -9,9 +9,10 @@ Events
|
||||
Solidity events give an abstraction on top of the EVM's logging functionality.
|
||||
Applications can subscribe and listen to these events through the RPC interface of an Ethereum client.
|
||||
|
||||
Events are inheritable members of contracts. When you call them, they cause the
|
||||
Events can be defined at file level or as inheritable members of contracts (including interfaces and libraries).
|
||||
When you call them, they cause the
|
||||
arguments to be stored in the transaction's log - a special data structure
|
||||
in the blockchain. These logs are associated with the address of the contract,
|
||||
in the blockchain. These logs are associated with the address of the contract that emitted them,
|
||||
are incorporated into the blockchain, and stay there as long as a block is
|
||||
accessible (forever as of now, but this might
|
||||
change with Serenity). The Log and its event data is not accessible from within
|
||||
|
@ -22,6 +22,7 @@ sourceUnit: (
|
||||
| enumDefinition
|
||||
| userDefinedValueTypeDefinition
|
||||
| errorDefinition
|
||||
| eventDefinition
|
||||
)* EOF;
|
||||
|
||||
//@doc: inline
|
||||
|
@ -112,11 +112,11 @@ Events are convenience interfaces with the EVM logging facilities.
|
||||
.. code-block:: solidity
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.21 <0.9.0;
|
||||
pragma solidity ^0.8.22;
|
||||
|
||||
contract SimpleAuction {
|
||||
event HighestBidIncreased(address bidder, uint amount); // Event
|
||||
|
||||
contract SimpleAuction {
|
||||
function bid() public payable {
|
||||
// ...
|
||||
emit HighestBidIncreased(msg.sender, msg.value); // Triggering event
|
||||
|
@ -131,6 +131,9 @@ ASTPointer<SourceUnit> Parser::parse(CharStream& _charStream)
|
||||
case Token::Function:
|
||||
nodes.push_back(parseFunctionDefinition(true));
|
||||
break;
|
||||
case Token::Event:
|
||||
nodes.push_back(parseEventDefinition());
|
||||
break;
|
||||
default:
|
||||
if (
|
||||
// Workaround because `error` is not a keyword.
|
||||
|
107
test/libsolidity/ABIJson/event_file_level.sol
Normal file
107
test/libsolidity/ABIJson/event_file_level.sol
Normal file
@ -0,0 +1,107 @@
|
||||
event Event();
|
||||
event Event(uint);
|
||||
|
||||
event UnusedEvent();
|
||||
|
||||
function f() {
|
||||
emit Event();
|
||||
}
|
||||
|
||||
contract C {
|
||||
function c_main() public {
|
||||
emit Event(42);
|
||||
f();
|
||||
}
|
||||
}
|
||||
|
||||
contract D is C {
|
||||
event Event(string);
|
||||
|
||||
function d_main() public {
|
||||
emit Event("abc");
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// :C
|
||||
// [
|
||||
// {
|
||||
// "anonymous": false,
|
||||
// "inputs": [],
|
||||
// "name": "Event",
|
||||
// "type": "event"
|
||||
// },
|
||||
// {
|
||||
// "anonymous": false,
|
||||
// "inputs":
|
||||
// [
|
||||
// {
|
||||
// "indexed": false,
|
||||
// "internalType": "uint256",
|
||||
// "name": "",
|
||||
// "type": "uint256"
|
||||
// }
|
||||
// ],
|
||||
// "name": "Event",
|
||||
// "type": "event"
|
||||
// },
|
||||
// {
|
||||
// "inputs": [],
|
||||
// "name": "c_main",
|
||||
// "outputs": [],
|
||||
// "stateMutability": "nonpayable",
|
||||
// "type": "function"
|
||||
// }
|
||||
// ]
|
||||
//
|
||||
//
|
||||
// :D
|
||||
// [
|
||||
// {
|
||||
// "anonymous": false,
|
||||
// "inputs": [],
|
||||
// "name": "Event",
|
||||
// "type": "event"
|
||||
// },
|
||||
// {
|
||||
// "anonymous": false,
|
||||
// "inputs":
|
||||
// [
|
||||
// {
|
||||
// "indexed": false,
|
||||
// "internalType": "uint256",
|
||||
// "name": "",
|
||||
// "type": "uint256"
|
||||
// }
|
||||
// ],
|
||||
// "name": "Event",
|
||||
// "type": "event"
|
||||
// },
|
||||
// {
|
||||
// "anonymous": false,
|
||||
// "inputs":
|
||||
// [
|
||||
// {
|
||||
// "indexed": false,
|
||||
// "internalType": "string",
|
||||
// "name": "",
|
||||
// "type": "string"
|
||||
// }
|
||||
// ],
|
||||
// "name": "Event",
|
||||
// "type": "event"
|
||||
// },
|
||||
// {
|
||||
// "inputs": [],
|
||||
// "name": "c_main",
|
||||
// "outputs": [],
|
||||
// "stateMutability": "nonpayable",
|
||||
// "type": "function"
|
||||
// },
|
||||
// {
|
||||
// "inputs": [],
|
||||
// "name": "d_main",
|
||||
// "outputs": [],
|
||||
// "stateMutability": "nonpayable",
|
||||
// "type": "function"
|
||||
// }
|
||||
// ]
|
@ -274,7 +274,7 @@ std::optional<AnnotatedEventSignature> SemanticTest::matchEvent(util::h256 const
|
||||
for (std::string& contractName: m_compiler.contractNames())
|
||||
{
|
||||
ContractDefinition const& contract = m_compiler.contractDefinition(contractName);
|
||||
for (EventDefinition const* event: contract.events())
|
||||
for (EventDefinition const* event: contract.events() + contract.usedInterfaceEvents())
|
||||
{
|
||||
FunctionTypePointer eventFunctionType = event->functionType(true);
|
||||
if (!event->isAnonymous() && keccak256(eventFunctionType->externalSignature()) == hash)
|
||||
|
39
test/libsolidity/natspecJSON/emit_file_level_event.sol
Normal file
39
test/libsolidity/natspecJSON/emit_file_level_event.sol
Normal file
@ -0,0 +1,39 @@
|
||||
/// @notice Userdoc for file-level event E.
|
||||
/// @dev Devdoc for file-level E.
|
||||
event E();
|
||||
|
||||
contract C {
|
||||
function f() public {
|
||||
emit E();
|
||||
}
|
||||
}
|
||||
|
||||
// ----
|
||||
// ----
|
||||
// :C devdoc
|
||||
// {
|
||||
// "events":
|
||||
// {
|
||||
// "E()":
|
||||
// {
|
||||
// "details": "Devdoc for file-level E."
|
||||
// }
|
||||
// },
|
||||
// "kind": "dev",
|
||||
// "methods": {},
|
||||
// "version": 1
|
||||
// }
|
||||
//
|
||||
// :C userdoc
|
||||
// {
|
||||
// "events":
|
||||
// {
|
||||
// "E()":
|
||||
// {
|
||||
// "notice": "Userdoc for file-level event E."
|
||||
// }
|
||||
// },
|
||||
// "kind": "user",
|
||||
// "methods": {},
|
||||
// "version": 1
|
||||
// }
|
@ -0,0 +1,69 @@
|
||||
/// @notice Userdoc for file-level event E.
|
||||
/// @dev Devdoc for file-level E.
|
||||
event E();
|
||||
|
||||
contract C {
|
||||
function f() public {
|
||||
emit E();
|
||||
}
|
||||
}
|
||||
|
||||
contract D is C {}
|
||||
|
||||
// ----
|
||||
// ----
|
||||
// :C devdoc
|
||||
// {
|
||||
// "events":
|
||||
// {
|
||||
// "E()":
|
||||
// {
|
||||
// "details": "Devdoc for file-level E."
|
||||
// }
|
||||
// },
|
||||
// "kind": "dev",
|
||||
// "methods": {},
|
||||
// "version": 1
|
||||
// }
|
||||
//
|
||||
// :C userdoc
|
||||
// {
|
||||
// "events":
|
||||
// {
|
||||
// "E()":
|
||||
// {
|
||||
// "notice": "Userdoc for file-level event E."
|
||||
// }
|
||||
// },
|
||||
// "kind": "user",
|
||||
// "methods": {},
|
||||
// "version": 1
|
||||
// }
|
||||
//
|
||||
// :D devdoc
|
||||
// {
|
||||
// "events":
|
||||
// {
|
||||
// "E()":
|
||||
// {
|
||||
// "details": "Devdoc for file-level E."
|
||||
// }
|
||||
// },
|
||||
// "kind": "dev",
|
||||
// "methods": {},
|
||||
// "version": 1
|
||||
// }
|
||||
//
|
||||
// :D userdoc
|
||||
// {
|
||||
// "events":
|
||||
// {
|
||||
// "E()":
|
||||
// {
|
||||
// "notice": "Userdoc for file-level event E."
|
||||
// }
|
||||
// },
|
||||
// "kind": "user",
|
||||
// "methods": {},
|
||||
// "version": 1
|
||||
// }
|
@ -0,0 +1,60 @@
|
||||
/// @notice Userdoc for file-level event E.
|
||||
/// @dev Devdoc for file-level E.
|
||||
event E();
|
||||
|
||||
contract F {
|
||||
/// @notice Userdoc for event F.E.
|
||||
/// @dev Devdoc for event F.E.
|
||||
event E();
|
||||
}
|
||||
|
||||
contract C {
|
||||
function f() public {
|
||||
emit E();
|
||||
emit F.E();
|
||||
}
|
||||
}
|
||||
|
||||
// ----
|
||||
// ----
|
||||
// :C devdoc
|
||||
// {
|
||||
// "kind": "dev",
|
||||
// "methods": {},
|
||||
// "version": 1
|
||||
// }
|
||||
//
|
||||
// :C userdoc
|
||||
// {
|
||||
// "kind": "user",
|
||||
// "methods": {},
|
||||
// "version": 1
|
||||
// }
|
||||
//
|
||||
// :F devdoc
|
||||
// {
|
||||
// "events":
|
||||
// {
|
||||
// "E()":
|
||||
// {
|
||||
// "details": "Devdoc for event F.E."
|
||||
// }
|
||||
// },
|
||||
// "kind": "dev",
|
||||
// "methods": {},
|
||||
// "version": 1
|
||||
// }
|
||||
//
|
||||
// :F userdoc
|
||||
// {
|
||||
// "events":
|
||||
// {
|
||||
// "E()":
|
||||
// {
|
||||
// "notice": "Userdoc for event F.E."
|
||||
// }
|
||||
// },
|
||||
// "kind": "user",
|
||||
// "methods": {},
|
||||
// "version": 1
|
||||
// }
|
21
test/libsolidity/natspecJSON/unused_file_level_event.sol
Normal file
21
test/libsolidity/natspecJSON/unused_file_level_event.sol
Normal file
@ -0,0 +1,21 @@
|
||||
/// @notice Userdoc for file-level event E.
|
||||
/// @dev Devdoc for file-level E.
|
||||
event E();
|
||||
|
||||
contract C {}
|
||||
|
||||
// ----
|
||||
// ----
|
||||
// :C devdoc
|
||||
// {
|
||||
// "kind": "dev",
|
||||
// "methods": {},
|
||||
// "version": 1
|
||||
// }
|
||||
//
|
||||
// :C userdoc
|
||||
// {
|
||||
// "kind": "user",
|
||||
// "methods": {},
|
||||
// "version": 1
|
||||
// }
|
@ -0,0 +1,10 @@
|
||||
event Deposit(address indexed _from, bytes32 indexed _id, uint _value);
|
||||
|
||||
contract ClientReceipt {
|
||||
function deposit(bytes32 _id) public payable {
|
||||
emit Deposit(msg.sender, _id, msg.value);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// deposit(bytes32), 18 wei: 0x1234 ->
|
||||
// ~ emit Deposit(address,bytes32,uint256): #0x1212121212121212121212121212120000000012, #0x1234, 0x12
|
@ -0,0 +1,15 @@
|
||||
event E();
|
||||
|
||||
library L {
|
||||
event E();
|
||||
}
|
||||
|
||||
contract C {
|
||||
function main() external pure returns (bytes32, bytes32) {
|
||||
assert(E.selector == L.E.selector);
|
||||
|
||||
return (E.selector, L.E.selector);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// main() -> 0x92bbf6e823a631f3c8e09b1c8df90f378fb56f7fbc9701827e1ff8aad7f6a028, 0x92bbf6e823a631f3c8e09b1c8df90f378fb56f7fbc9701827e1ff8aad7f6a028
|
@ -0,0 +1,38 @@
|
||||
event E();
|
||||
|
||||
library L1 {
|
||||
event E(string);
|
||||
}
|
||||
|
||||
library L2 {
|
||||
event E();
|
||||
}
|
||||
|
||||
library K {
|
||||
function main() internal pure returns (bytes32, bytes32, bytes32) {
|
||||
// Here E is the global event.
|
||||
assert(E.selector != L1.E.selector);
|
||||
assert(E.selector == L2.E.selector);
|
||||
|
||||
return (E.selector, L1.E.selector, L2.E.selector);
|
||||
}
|
||||
}
|
||||
|
||||
contract C {
|
||||
event E(string);
|
||||
|
||||
function main() external pure returns (bytes32, bytes32, bytes32) {
|
||||
// Here E is the local event.
|
||||
assert(E.selector == L1.E.selector);
|
||||
assert(E.selector != L2.E.selector);
|
||||
|
||||
return (E.selector, L1.E.selector, L2.E.selector);
|
||||
}
|
||||
|
||||
function k_main() external pure returns (bytes32, bytes32, bytes32) {
|
||||
return K.main();
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// main() -> 0x3e9992c940c54ea252d3a34557cc3d3014281525c43d694f89d5f3dfd820b07d, 0x3e9992c940c54ea252d3a34557cc3d3014281525c43d694f89d5f3dfd820b07d, 0x92bbf6e823a631f3c8e09b1c8df90f378fb56f7fbc9701827e1ff8aad7f6a028
|
||||
// k_main() -> 0x92bbf6e823a631f3c8e09b1c8df90f378fb56f7fbc9701827e1ff8aad7f6a028, 0x3e9992c940c54ea252d3a34557cc3d3014281525c43d694f89d5f3dfd820b07d, 0x92bbf6e823a631f3c8e09b1c8df90f378fb56f7fbc9701827e1ff8aad7f6a028
|
@ -0,0 +1,32 @@
|
||||
event Deposit();
|
||||
event Deposit(address _addr);
|
||||
event Deposit(address _addr, uint _amount);
|
||||
event Deposit(address _addr, bool _flag);
|
||||
|
||||
contract ClientReceipt {
|
||||
function deposit() public returns (uint) {
|
||||
emit Deposit();
|
||||
return 1;
|
||||
}
|
||||
function deposit(address _addr) public returns (uint) {
|
||||
emit Deposit(_addr);
|
||||
return 2;
|
||||
}
|
||||
function deposit(address _addr, uint _amount) public returns (uint) {
|
||||
emit Deposit(_addr, _amount);
|
||||
return 3;
|
||||
}
|
||||
function deposit(address _addr, bool _flag) public returns (uint) {
|
||||
emit Deposit(_addr, _flag);
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// deposit() -> 1
|
||||
// ~ emit Deposit()
|
||||
// deposit(address): 0x5082a85c489be6aa0f2e6693bf09cc1bbd35e988 -> 2
|
||||
// ~ emit Deposit(address): 0x5082a85c489be6aa0f2e6693bf09cc1bbd35e988
|
||||
// deposit(address,uint256): 0x5082a85c489be6aa0f2e6693bf09cc1bbd35e988, 100 -> 3
|
||||
// ~ emit Deposit(address,uint256): 0x5082a85c489be6aa0f2e6693bf09cc1bbd35e988, 0x64
|
||||
// deposit(address,bool): 0x5082a85c489be6aa0f2e6693bf09cc1bbd35e988, false -> 4
|
||||
// ~ emit Deposit(address,bool): 0x5082a85c489be6aa0f2e6693bf09cc1bbd35e988, false
|
@ -0,0 +1,8 @@
|
||||
==== Source: M.sol ====
|
||||
event E();
|
||||
==== Source: A.sol ====
|
||||
import "M.sol" as M;
|
||||
|
||||
function f() {
|
||||
emit M.E();
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
event E();
|
||||
|
||||
contract C {
|
||||
function f() public {
|
||||
emit E();
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
event E();
|
||||
|
||||
contract C {
|
||||
function f() external pure returns (bytes32) {
|
||||
return E.selector;
|
||||
}
|
||||
}
|
11
test/libsolidity/syntaxTests/events/file_level_event.sol
Normal file
11
test/libsolidity/syntaxTests/events/file_level_event.sol
Normal file
@ -0,0 +1,11 @@
|
||||
event E1();
|
||||
event E2(uint);
|
||||
event E3(uint, string indexed, bytes, bool);
|
||||
event E4(int, int, int) anonymous;
|
||||
|
||||
function f() {
|
||||
emit E1();
|
||||
emit E2(1);
|
||||
emit E3(1, "abc", "abc", true);
|
||||
emit E4(1, 2, 3);
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
event E();
|
||||
event E();
|
||||
// ----
|
||||
// DeclarationError 5883: (0-10): Event with same name and parameter types defined twice.
|
@ -0,0 +1,8 @@
|
||||
==== Source: A.sol ====
|
||||
event E();
|
||||
==== Source: B.sol ====
|
||||
import "A.sol";
|
||||
|
||||
event E();
|
||||
// ----
|
||||
// DeclarationError 5883: (B.sol:17-27): Event with same name and parameter types defined twice.
|
@ -0,0 +1,12 @@
|
||||
==== Source: A.sol ====
|
||||
event EA();
|
||||
==== Source: B.sol ====
|
||||
event EB();
|
||||
==== Source: C.sol ====
|
||||
import "A.sol";
|
||||
import {EB} from "B.sol";
|
||||
|
||||
function f() {
|
||||
emit EA();
|
||||
emit EB();
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
event E();
|
||||
event E(uint);
|
||||
event E(uint, string indexed, bytes, bool);
|
||||
event E(int, int, int) anonymous;
|
||||
|
||||
function f() {
|
||||
emit E();
|
||||
emit E(1);
|
||||
emit E(1, "abc", "abc", true);
|
||||
emit E(1, 2, 3);
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
event E();
|
||||
|
||||
contract C {
|
||||
event E(uint);
|
||||
|
||||
function f() public {
|
||||
emit E();
|
||||
emit E(1);
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 2519: (29-43): This declaration shadows an existing declaration.
|
||||
// TypeError 6160: (84-87): Wrong argument count for function call: 0 arguments given but expected 1.
|
@ -0,0 +1,17 @@
|
||||
event E();
|
||||
|
||||
contract C {
|
||||
event E();
|
||||
}
|
||||
|
||||
library L {
|
||||
event E();
|
||||
}
|
||||
|
||||
interface I {
|
||||
event E();
|
||||
}
|
||||
// ----
|
||||
// Warning 2519: (29-39): This declaration shadows an existing declaration.
|
||||
// Warning 2519: (59-69): This declaration shadows an existing declaration.
|
||||
// Warning 2519: (91-101): This declaration shadows an existing declaration.
|
@ -0,0 +1,17 @@
|
||||
event E();
|
||||
|
||||
contract C {
|
||||
event E() anonymous;
|
||||
}
|
||||
|
||||
library L {
|
||||
event E() anonymous;
|
||||
}
|
||||
|
||||
interface I {
|
||||
event E() anonymous;
|
||||
}
|
||||
// ----
|
||||
// Warning 2519: (29-49): This declaration shadows an existing declaration.
|
||||
// Warning 2519: (69-89): This declaration shadows an existing declaration.
|
||||
// Warning 2519: (111-131): This declaration shadows an existing declaration.
|
@ -0,0 +1,4 @@
|
||||
event E();
|
||||
contract E {}
|
||||
// ----
|
||||
// DeclarationError 2333: (11-24): Identifier already declared.
|
@ -0,0 +1,4 @@
|
||||
event E();
|
||||
error E();
|
||||
// ----
|
||||
// DeclarationError 2333: (11-21): Identifier already declared.
|
@ -0,0 +1,6 @@
|
||||
event E();
|
||||
|
||||
type T is uint;
|
||||
using {E} for T;
|
||||
// ----
|
||||
// TypeError 8187: (35-36): Expected function name.
|
@ -0,0 +1,4 @@
|
||||
// Exception for the illegal name list. External interface events
|
||||
event this();
|
||||
event super();
|
||||
event _();
|
Loading…
Reference in New Issue
Block a user