diff options
56 files changed, 1690 insertions, 109 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index f30872af..20b4d97b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ include(EthPolicy) eth_policy() # project name and version should be set after cmake_policy CMP0048 -set(PROJECT_VERSION "0.4.25") +set(PROJECT_VERSION "0.4.26") project(solidity VERSION ${PROJECT_VERSION}) option(SOLC_LINK_STATIC "Link solc executable statically on supported platforms" OFF) diff --git a/Changelog.md b/Changelog.md index 846ae1f5..2619801f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -7,6 +7,7 @@ How to update your code: * Make your fallback functions ``external``. * Explicitly state the data location for all variables of struct, array or mapping types (including function parameters), e.g. change ``uint[] x = m_x`` to ``uint[] storage x = m_x``. Note that ``external`` functions require parameters with a data location of ``calldata``. * Explicitly convert values of contract type to addresses before using an ``address`` member. Example: if ``c`` is a contract, change ``c.transfer(...)`` to ``address(c).transfer(...)``. + * Declare variables and especially function arguments as ``address payable``, if you want to call ``transfer`` on them. Breaking Changes: * ABI Encoder: Properly pad data from calldata (``msg.data`` and external function parameters). Use ``abi.encodePacked`` for unpadded encoding. @@ -62,6 +63,7 @@ Breaking Changes: * Type Checker: Disallow "loose assembly" syntax entirely. This means that jump labels, jumps and non-functional instructions cannot be used anymore. * Type System: Disallow explicit and implicit conversions from decimal literals to ``bytesXX`` types. * Type System: Disallow explicit and implicit conversions from hex literals to ``bytesXX`` types of different size. + * Type System: Distinguish between payable and non-payable address types. * View Pure Checker: Disallow ``msg.value`` in (or introducing it via a modifier to) a non-payable function. * Remove obsolete ``std`` directory from the Solidity repository. This means accessing ``https://github.com/ethereum/solidity/blob/develop/std/*.sol`` (or ``https://github.com/ethereum/solidity/std/*.sol`` in Remix) will not be possible. * References Resolver: Turn missing storage locations into an error. This was already the case in the experimental 0.5.0 mode. @@ -92,9 +94,6 @@ Compiler Features: * Code Generator: Allocate and free local variables according to their scope. * Removed ``pragma experimental "v0.5.0";``. -Critical Bugfixes: - * Code Generator: Properly perform cleanup for exponentiation and non-256 bit types. - Bugfixes: * Build System: Support versions of CVC4 linked against CLN instead of GMP. In case of compilation issues due to the experimental SMT solver support, the solvers can be disabled when configuring the project with CMake using ``-DUSE_CVC4=OFF`` or ``-DUSE_Z3=OFF``. * Tests: Fix chain parameters to make ipc tests work with newer versions of cpp-ethereum. @@ -115,13 +114,19 @@ Bugfixes: * Type Checker: Consider fixed size arrays when checking for recursive structs. * Type Checker: Fix crashes in erroneous tuple assignments in which the type of the right hand side cannot be determined. * Type Checker: Fix freeze for negative fixed-point literals very close to ``0``, such as ``-1e-100``. - * Type Checker: Report error when using structs in events without experimental ABIEncoderV2. This used to crash or log the wrong values. - * Type Checker: Report error when using indexed structs in events with experimental ABIEncoderV2. This used to log wrong values. * Type Checker: Dynamic types as key for public mappings return error instead of assertion fail. * Type Checker: Fix internal error when array index value is too large. * Type System: Allow arbitrary exponents for literals with a mantissa of zero. * Parser: Fix incorrect source location for nameless parameters. - * Parser: Treat unicode line endings as terminating strings and single-line comments. + +### 0.4.25 (2018-09-12) + +Important Bugfixes: + * Code Generator: Properly perform cleanup for exponentiation and non-256 bit types. + * Type Checker: Report error when using indexed structs in events with experimental ABIEncoderV2. This used to log wrong values. + * Type Checker: Report error when using structs in events without experimental ABIEncoderV2. This used to crash or log the wrong values. + * Parser: Consider all unicode line terminators (LF, VF, FF, CR, NEL, LS, PS) for single-line comments + and string literals. They are invalid in strings and will end comments. * Parser: Disallow unterminated multi-line comments at the end of input. * Parser: Treat ``/** /`` as unterminated multi-line comment. diff --git a/docs/assembly.rst b/docs/assembly.rst index 2cbad06f..91935293 100644 --- a/docs/assembly.rst +++ b/docs/assembly.rst @@ -141,6 +141,8 @@ these curly braces, the following can be used (see the later sections for more d - assignments in functional style, e.g. ``x := add(y, 3)`` - blocks where local variables are scoped inside, e.g. ``{ let x := 3 { let y := add(x, 1) } }`` +.. _opcodes: + Opcodes ------- diff --git a/docs/bugs.json b/docs/bugs.json index 980b3897..28c0fe62 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -12,7 +12,7 @@ "summary": "Using structs in events logged wrong data.", "description": "If a struct is used in an event, the address of the struct is logged instead of the actual data.", "introduced": "0.4.17", - "fixed": "0.5.0", + "fixed": "0.4.25", "severity": "very low", "check": {"ast-compact-json-path": "$..[?(@.nodeType === 'EventDefinition')]..[?(@.nodeType === 'UserDefinedTypeName' && @.typeDescriptions.typeString.startsWith('struct'))]"} }, diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index 96cc3c5c..0318ac89 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -515,6 +515,10 @@ ], "released": "2018-05-16" }, + "0.4.25": { + "bugs": [], + "released": "2018-09-12" + }, "0.4.3": { "bugs": [ "ExpExponentCleanup", diff --git a/docs/common-patterns.rst b/docs/common-patterns.rst index 6b061bf7..d26e4377 100644 --- a/docs/common-patterns.rst +++ b/docs/common-patterns.rst @@ -68,7 +68,7 @@ This is as opposed to the more intuitive sending pattern: pragma solidity >0.4.24; contract SendContract { - address public richest; + address payable public richest; uint public mostSent; constructor() public payable { diff --git a/docs/contracts.rst b/docs/contracts.rst index 8fd1c89e..b9179b27 100644 --- a/docs/contracts.rst +++ b/docs/contracts.rst @@ -334,7 +334,7 @@ inheritable properties of contracts and may be overridden by derived contracts. contract owned { constructor() public { owner = msg.sender; } - address owner; + address payable owner; // This contract only defines a modifier but does not use // it: it will be used in derived contracts. @@ -650,9 +650,14 @@ Like any function, the fallback function can execute complex operations as long require(success); // results in test.x becoming == 1. + // address(test) will not allow to call ``send`` directly, since ``test`` has no payable + // fallback function. It has to be converted to the ``address payable`` type via an + // intermediate conversion to ``uint160`` to even allow calling ``send`` on it. + address payable testPayable = address(uint160(address(test))); + // If someone sends ether to that contract, // the transfer will fail, i.e. this returns false here. - return address(test).send(2 ether); + return testPayable.send(2 ether); } } @@ -891,7 +896,7 @@ Details are given in the following example. contract owned { constructor() public { owner = msg.sender; } - address owner; + address payable owner; } // Use `is` to derive from another contract. Derived @@ -963,7 +968,7 @@ seen in the following example:: contract owned { constructor() public { owner = msg.sender; } - address owner; + address payable owner; } contract mortal is owned { @@ -992,7 +997,7 @@ derived override, but this function will bypass contract owned { constructor() public { owner = msg.sender; } - address owner; + address payable owner; } contract mortal is owned { diff --git a/docs/control-structures.rst b/docs/control-structures.rst index 5810aaa7..745a0599 100644 --- a/docs/control-structures.rst +++ b/docs/control-structures.rst @@ -421,7 +421,7 @@ a message string for ``require``, but not for ``assert``. pragma solidity >0.4.24; contract Sharer { - function sendHalf(address addr) public payable returns (uint balance) { + function sendHalf(address payable addr) public payable returns (uint balance) { require(msg.value % 2 == 0, "Even value required."); uint balanceBeforeTransfer = address(this).balance; addr.transfer(msg.value / 2); diff --git a/docs/introduction-to-smart-contracts.rst b/docs/introduction-to-smart-contracts.rst index 7de0d19b..bd30a8fd 100644 --- a/docs/introduction-to-smart-contracts.rst +++ b/docs/introduction-to-smart-contracts.rst @@ -359,36 +359,38 @@ Gas Upon creation, each transaction is charged with a certain amount of **gas**, whose purpose is to limit the amount of work that is needed to execute -the transaction and to pay for this execution. While the EVM executes the +the transaction and to pay for this execution at the same time. While the EVM executes the transaction, the gas is gradually depleted according to specific rules. The **gas price** is a value set by the creator of the transaction, who has to pay ``gas_price * gas`` up front from the sending account. -If some gas is left after the execution, it is refunded in the same way. +If some gas is left after the execution, it is refunded to the creator in the same way. -If the gas is used up at any point (i.e. it is negative), +If the gas is used up at any point (i.e. it would be negative), an out-of-gas exception is triggered, which reverts all modifications made to the state in the current call frame. -Any unused gas is refunded at the end of the transaction. - .. index:: ! storage, ! memory, ! stack Storage, Memory and the Stack ============================= -The Ethereum Virtual Machine has three areas where it can store data. +The Ethereum Virtual Machine has three areas where it can store data, +storage, memory and the stack, which are explained in the following +paragraphs. -Each account has a data area called **storage**, which is persistent between function calls. +Each account has a data area called **storage**, which is persistent between function calls +and transactions. Storage is a key-value store that maps 256-bit words to 256-bit words. -It is not possible to enumerate storage from within a contract and it is comparatively costly to read, and even more to modify storage. +It is not possible to enumerate storage from within a contract and it is +comparatively costly to read, and even more to modify storage. A contract can neither read nor write to any storage apart from its own. The second data area is called **memory**, of which a contract obtains a freshly cleared instance for each message call. Memory is linear and can be addressed at byte level, but reads are limited to a width of 256 bits, while writes can be either 8 bits or 256 bits wide. Memory is expanded by a word (256-bit), when -accessing (either reading or writing) a previously untouched memory word (ie. any offset +accessing (either reading or writing) a previously untouched memory word (i.e. any offset within a word). At the time of expansion, the cost in gas must be paid. Memory is more costly the larger it grows (it scales quadratically). @@ -401,7 +403,8 @@ the topmost 16 elements to the top of the stack or swap the topmost element with one of the 16 elements below it. All other operations take the topmost two (or one, or more, depending on the operation) elements from the stack and push the result onto the stack. -Of course it is possible to move stack elements to storage or memory, +Of course it is possible to move stack elements to storage or memory +in order to get deeper access to the stack, but it is not possible to just access arbitrary elements deeper in the stack without first removing the top of the stack. @@ -411,13 +414,17 @@ Instruction Set =============== The instruction set of the EVM is kept minimal in order to avoid -incorrect implementations which could cause consensus problems. -All instructions operate on the basic data type, 256-bit words. +incorrect or inconsistent implementations which could cause consensus problems. +All instructions operate on the basic data type, 256-bit words or on slices of memory +(or other byte arrays). The usual arithmetic, bit, logical and comparison operations are present. Conditional and unconditional jumps are possible. Furthermore, contracts can access relevant properties of the current block like its number and timestamp. +For a complete list, please see the :ref:`list of opcodes <opcodes>` as part of the inline +assembly documentation. + .. index:: ! message call, function;call Message Calls @@ -442,9 +449,12 @@ will receive a freshly cleared instance of memory and has access to the call payload - which will be provided in a separate area called the **calldata**. After it has finished execution, it can return data which will be stored at a location in the caller's memory preallocated by the caller. +All such calls are fully synchronous. Calls are **limited** to a depth of 1024, which means that for more complex -operations, loops should be preferred over recursive calls. +operations, loops should be preferred over recursive calls. Furthermore, +only 63/64th of the gas can be forwarded in a message call, which causes a +depth limit of a little less than 1000 in practice. .. index:: delegatecall, callcode, library @@ -462,7 +472,7 @@ refer to the calling contract, only the code is taken from the called address. This makes it possible to implement the "library" feature in Solidity: Reusable library code that can be applied to a contract's storage, e.g. in -order to implement a complex data structure. +order to implement a complex data structure. .. index:: log @@ -471,13 +481,13 @@ Logs It is possible to store data in a specially indexed data structure that maps all the way up to the block level. This feature called **logs** -is used by Solidity in order to implement **events**. +is used by Solidity in order to implement :ref:`events <events>`. Contracts cannot access log data after it has been created, but they can be efficiently accessed from outside the blockchain. Since some part of the log data is stored in `bloom filters <https://en.wikipedia.org/wiki/Bloom_filter>`_, it is possible to search for this data in an efficient and cryptographically secure way, so network peers that do not download the whole blockchain -("light clients") can still find these logs. +(so-called "light clients") can still find these logs. .. index:: contract creation @@ -485,7 +495,7 @@ Create ====== Contracts can even create other contracts using a special opcode (i.e. -they do not simply call the zero address). The only difference between +they do not simply call the zero address as a transaction would). The only difference between these **create calls** and normal message calls is that the payload data is executed and the result stored as code and the caller / creator receives the address of the new contract on the stack. diff --git a/docs/miscellaneous.rst b/docs/miscellaneous.rst index 87041be6..d96ff166 100644 --- a/docs/miscellaneous.rst +++ b/docs/miscellaneous.rst @@ -329,7 +329,7 @@ Global Variables starting from the second and prepends the given four-byte selector - ``abi.encodeWithSignature(string signature, ...) returns (bytes)``: Equivalent to ``abi.encodeWithSelector(bytes4(keccak256(bytes(signature)), ...)``` - ``block.blockhash(uint blockNumber) returns (bytes32)``: hash of the given block - only works for 256 most recent, excluding current, blocks - deprecated in version 0.4.22 and replaced by ``blockhash(uint blockNumber)``. -- ``block.coinbase`` (``address``): current block miner's address +- ``block.coinbase`` (``address payable``): current block miner's address - ``block.difficulty`` (``uint``): current block difficulty - ``block.gaslimit`` (``uint``): current block gaslimit - ``block.number`` (``uint``): current block number @@ -337,11 +337,11 @@ Global Variables - ``gasleft() returns (uint256)``: remaining gas - ``msg.data`` (``bytes``): complete calldata - ``msg.gas`` (``uint``): remaining gas - deprecated in version 0.4.21 and to be replaced by ``gasleft()`` -- ``msg.sender`` (``address``): sender of the message (current call) +- ``msg.sender`` (``address payable``): sender of the message (current call) - ``msg.value`` (``uint``): number of wei sent with the message - ``now`` (``uint``): current block timestamp (alias for ``block.timestamp``) - ``tx.gasprice`` (``uint``): gas price of the transaction -- ``tx.origin`` (``address``): sender of the transaction (full call chain) +- ``tx.origin`` (``address payable``): sender of the transaction (full call chain) - ``assert(bool condition)``: abort execution and revert state changes if condition is ``false`` (use for internal error) - ``require(bool condition)``: abort execution and revert state changes if condition is ``false`` (use for malformed input or error in external component) - ``require(bool condition, string message)``: abort execution and revert state changes if condition is ``false`` (use for malformed input or error in external component). Also provide error message. @@ -360,8 +360,8 @@ Global Variables - ``selfdestruct(address recipient)``: destroy the current contract, sending its funds to the given address - ``suicide(address recipient)``: a deprecated alias to ``selfdestruct`` - ``<address>.balance`` (``uint256``): balance of the :ref:`address` in Wei -- ``<address>.send(uint256 amount) returns (bool)``: send given amount of Wei to :ref:`address`, returns ``false`` on failure -- ``<address>.transfer(uint256 amount)``: send given amount of Wei to :ref:`address`, throws on failure +- ``<address payable>.send(uint256 amount) returns (bool)``: send given amount of Wei to :ref:`address`, returns ``false`` on failure +- ``<address payable>.transfer(uint256 amount)``: send given amount of Wei to :ref:`address`, throws on failure .. note:: Do not rely on ``block.timestamp``, ``now`` and ``blockhash`` as a source of randomness, diff --git a/docs/security-considerations.rst b/docs/security-considerations.rst index 3bcd9566..8df12b7c 100644 --- a/docs/security-considerations.rst +++ b/docs/security-considerations.rst @@ -192,7 +192,7 @@ Never use tx.origin for authorization. Let's say you have a wallet contract like owner = msg.sender; } - function transferTo(address dest, uint amount) public { + function transferTo(address payable dest, uint amount) public { require(tx.origin == owner); dest.transfer(amount); } @@ -205,11 +205,11 @@ Now someone tricks you into sending ether to the address of this attack wallet: pragma solidity >0.4.24; interface TxUserWallet { - function transferTo(address dest, uint amount) external; + function transferTo(address payable dest, uint amount) external; } contract TxAttackWallet { - address owner; + address payable owner; constructor() public { owner = msg.sender; diff --git a/docs/solidity-by-example.rst b/docs/solidity-by-example.rst index 72b3581b..0b183ca5 100644 --- a/docs/solidity-by-example.rst +++ b/docs/solidity-by-example.rst @@ -231,7 +231,7 @@ activate themselves. // Parameters of the auction. Times are either // absolute unix timestamps (seconds since 1970-01-01) // or time periods in seconds. - address public beneficiary; + address payable public beneficiary; uint public auctionEndTime; // Current state of the auction. @@ -258,7 +258,7 @@ activate themselves. /// beneficiary address `_beneficiary`. constructor( uint _biddingTime, - address _beneficiary + address payable _beneficiary ) public { beneficiary = _beneficiary; auctionEndTime = now + _biddingTime; @@ -396,7 +396,7 @@ high or low invalid bids. uint deposit; } - address public beneficiary; + address payable public beneficiary; uint public biddingEnd; uint public revealEnd; bool public ended; @@ -421,7 +421,7 @@ high or low invalid bids. constructor( uint _biddingTime, uint _revealTime, - address _beneficiary + address payable _beneficiary ) public { beneficiary = _beneficiary; biddingEnd = now + _biddingTime; @@ -545,8 +545,8 @@ Safe Remote Purchase contract Purchase { uint public value; - address public seller; - address public buyer; + address payable public seller; + address payable public buyer; enum State { Created, Locked, Inactive } State public state; @@ -990,11 +990,11 @@ The full contract pragma solidity ^0.4.24; contract SimplePaymentChannel { - address public sender; // The account sending payments. - address public recipient; // The account receiving the payments. + address payable public sender; // The account sending payments. + address payable public recipient; // The account receiving the payments. uint256 public expiration; // Timeout in case the recipient never closes. - constructor (address _recipient, uint256 duration) + constructor (address payable _recipient, uint256 duration) public payable { diff --git a/docs/types.rst b/docs/types.rst index 03fd36d9..eaec8ad5 100644 --- a/docs/types.rst +++ b/docs/types.rst @@ -99,6 +99,15 @@ Address ------- ``address``: Holds a 20 byte value (size of an Ethereum address). Address types also have members and serve as a base for all contracts. +``address payable``: Same as ``address``, but with the additional members ``transfer`` and ``send``. + +Implicit conversions from ``address payable`` to ``address`` are allowed, whereas conversions from ``address`` to ``address payable`` are +not possible (the only way to perform such a conversion is by using an intermediate conversion to ``uint160``). +Conversions of the form ``address payable(x)`` are not allowed. Instead the result of a conversion of the form ``address(x)`` +has the type ``address payable``, if ``x`` is of integer or fixed bytes type, a literal or a contract with a payable fallback function. +If ``x`` is a contract without payable fallback function ``address(x)`` will be of type ``address``. The type of address literals +is ``address payable``. +In external function signatures ``address`` is used for both the ``address`` and the ``address payable`` type. Operators: @@ -113,7 +122,8 @@ Operators: or you can use ``address(uint160(uint256(b)))``, which results in ``0x777788889999AaAAbBbbCcccddDdeeeEfFFfCcCc``. .. note:: - Starting with version 0.5.0 contracts do not derive from the address type, but can still be explicitly converted to address. + Starting with version 0.5.0 contracts do not derive from the address type, but can still be explicitly converted to + ``address`` or to ``address payable``, if they have a payable fallback function. .. _members-of-addresses: @@ -125,11 +135,11 @@ Members of Addresses For a quick reference, see :ref:`address_related`. It is possible to query the balance of an address using the property ``balance`` -and to send Ether (in units of wei) to an address using the ``transfer`` function: +and to send Ether (in units of wei) to a payable address using the ``transfer`` function: :: - address x = 0x123; + address payable x = address(0x123); address myAddress = this; if (x.balance < 10 && myAddress.balance >= 10) x.transfer(10); @@ -211,11 +221,14 @@ Contract Types Every :ref:`contract<contracts>` defines its own type. You can implicitly convert contracts to contracts they inherit from, -and explicitly convert them to and from the ``address`` type. +and explicitly convert them to and from the ``address`` type, if they have no +payable fallback functions, or to and from the ``address payable`` type, if they do +have payable fallback functions. .. note:: Starting with version 0.5.0 contracts do not derive from the address type, - but can still be explicitly converted to address. + but can still be explicitly converted to ``address``, resp. to ``address payable``, + if they have a payable fallback function. If you declare a local variable of contract type (`MyContract c`), you can call functions on that contract. Take care to assign it from somewhere that is the @@ -860,7 +873,7 @@ shown in the following example: } struct Campaign { - address beneficiary; + address payable beneficiary; uint fundingGoal; uint numFunders; uint amount; @@ -870,7 +883,7 @@ shown in the following example: uint numCampaigns; mapping (uint => Campaign) campaigns; - function newCampaign(address beneficiary, uint goal) public returns (uint campaignID) { + function newCampaign(address payable beneficiary, uint goal) public returns (uint campaignID) { campaignID = numCampaigns++; // campaignID is return variable // Creates new struct and saves in storage. We leave out the mapping type. campaigns[campaignID] = Campaign(beneficiary, goal, 0, 0); diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst index 55911dc6..2e1b90a0 100644 --- a/docs/units-and-global-variables.rst +++ b/docs/units-and-global-variables.rst @@ -57,7 +57,7 @@ Block and Transaction Properties -------------------------------- - ``block.blockhash(uint blockNumber) returns (bytes32)``: hash of the given block - only works for 256 most recent, excluding current, blocks - deprecated in version 0.4.22 and replaced by ``blockhash(uint blockNumber)``. -- ``block.coinbase`` (``address``): current block miner's address +- ``block.coinbase`` (``address payable``): current block miner's address - ``block.difficulty`` (``uint``): current block difficulty - ``block.gaslimit`` (``uint``): current block gaslimit - ``block.number`` (``uint``): current block number @@ -65,12 +65,12 @@ Block and Transaction Properties - ``gasleft() returns (uint256)``: remaining gas - ``msg.data`` (``bytes``): complete calldata - ``msg.gas`` (``uint``): remaining gas - deprecated in version 0.4.21 and to be replaced by ``gasleft()`` -- ``msg.sender`` (``address``): sender of the message (current call) +- ``msg.sender`` (``address payable``): sender of the message (current call) - ``msg.sig`` (``bytes4``): first four bytes of the calldata (i.e. function identifier) - ``msg.value`` (``uint``): number of wei sent with the message - ``now`` (``uint``): current block timestamp (alias for ``block.timestamp``) - ``tx.gasprice`` (``uint``): gas price of the transaction -- ``tx.origin`` (``address``): sender of the transaction (full call chain) +- ``tx.origin`` (``address payable``): sender of the transaction (full call chain) .. note:: The values of all members of ``msg``, including ``msg.sender`` and @@ -161,9 +161,9 @@ Address Related ``<address>.balance`` (``uint256``): balance of the :ref:`address` in Wei -``<address>.transfer(uint256 amount)``: +``<address payable>.transfer(uint256 amount)``: send given amount of Wei to :ref:`address`, throws on failure, forwards 2300 gas stipend, not adjustable -``<address>.send(uint256 amount) returns (bool)``: +``<address payable>.send(uint256 amount) returns (bool)``: send given amount of Wei to :ref:`address`, returns ``false`` on failure, forwards 2300 gas stipend, not adjustable ``<address>.call(bytes memory) returns (bool)``: issue low-level ``CALL`` with the given payload, returns ``false`` on failure, forwards all available gas, adjustable @@ -204,10 +204,10 @@ Contract Related ``this`` (current contract's type): the current contract, explicitly convertible to :ref:`address` -``selfdestruct(address recipient)``: +``selfdestruct(address payable recipient)``: destroy the current contract, sending its funds to the given :ref:`address` -``suicide(address recipient)``: +``suicide(address payable recipient)``: deprecated alias to ``selfdestruct`` Furthermore, all functions of the current contract are callable directly including the current function. diff --git a/libsolidity/analysis/GlobalContext.cpp b/libsolidity/analysis/GlobalContext.cpp index 3ac8fd47..cba2655c 100644 --- a/libsolidity/analysis/GlobalContext.cpp +++ b/libsolidity/analysis/GlobalContext.cpp @@ -56,10 +56,10 @@ m_magicVariables(vector<shared_ptr<MagicVariableDeclaration const>>{ make_shared<MagicVariableDeclaration>("revert", make_shared<FunctionType>(strings(), strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)), make_shared<MagicVariableDeclaration>("revert", make_shared<FunctionType>(strings{"string memory"}, strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)), make_shared<MagicVariableDeclaration>("ripemd160", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes20"}, FunctionType::Kind::RIPEMD160, false, StateMutability::Pure)), - make_shared<MagicVariableDeclaration>("selfdestruct", make_shared<FunctionType>(strings{"address"}, strings{}, FunctionType::Kind::Selfdestruct)), + make_shared<MagicVariableDeclaration>("selfdestruct", make_shared<FunctionType>(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)), make_shared<MagicVariableDeclaration>("sha256", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::SHA256, false, StateMutability::Pure)), make_shared<MagicVariableDeclaration>("sha3", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)), - make_shared<MagicVariableDeclaration>("suicide", make_shared<FunctionType>(strings{"address"}, strings{}, FunctionType::Kind::Selfdestruct)), + make_shared<MagicVariableDeclaration>("suicide", make_shared<FunctionType>(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)), make_shared<MagicVariableDeclaration>("tx", make_shared<MagicType>(MagicType::Kind::Transaction)) }) { diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index 4b678c3b..8a576e2e 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -119,11 +119,19 @@ bool ReferencesResolver::visit(ElementaryTypeName const& _typeName) { // for non-address types this was already caught by the parser solAssert(_typeName.annotation().type->category() == Type::Category::Address, ""); - if (!( - *_typeName.stateMutability() == StateMutability::Payable || - *_typeName.stateMutability() == StateMutability::NonPayable - )) - m_errorReporter.typeError(_typeName.location(), "Address types can only be payable or non-payable."); + switch(*_typeName.stateMutability()) + { + case StateMutability::Payable: + case StateMutability::NonPayable: + _typeName.annotation().type = make_shared<AddressType>(*_typeName.stateMutability()); + break; + default: + m_errorReporter.typeError( + _typeName.location(), + "Address types can only be payable or non-payable." + ); + break; + } } } return true; diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 143ac109..e023dc38 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -571,6 +571,9 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c // data locations. Furthermore, storage can be a little dangerous and // calldata is not really implemented anyway. actualType = ReferenceType::copyForLocationIfReference(DataLocation::Memory, actualType); + // We force address payable for address types. + if (actualType->category() == Type::Category::Address) + actualType = make_shared<AddressType>(StateMutability::Payable); solAssert( !actualType->dataStoredIn(DataLocation::CallData) && !actualType->dataStoredIn(DataLocation::Storage), @@ -1732,14 +1735,39 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) dataLoc = argRefType->location(); resultType = ReferenceType::copyForLocationIfReference(dataLoc, resultType); if (!argType->isExplicitlyConvertibleTo(*resultType)) - m_errorReporter.typeError( - _functionCall.location(), - "Explicit type conversion not allowed from \"" + - argType->toString() + - "\" to \"" + - resultType->toString() + - "\"." - ); + { + if (resultType->category() == Type::Category::Contract && argType->category() == Type::Category::Address) + { + solAssert(dynamic_cast<ContractType const*>(resultType.get())->isPayable(), ""); + solAssert(dynamic_cast<AddressType const*>(argType.get())->stateMutability() < StateMutability::Payable, ""); + SecondarySourceLocation ssl; + if (auto const* identifier = dynamic_cast<Identifier const*>(arguments.front().get())) + if (auto const* variableDeclaration = dynamic_cast<VariableDeclaration const*>(identifier->annotation().referencedDeclaration)) + ssl.append("Did you mean to declare this variable as \"address payable\"?", variableDeclaration->location()); + m_errorReporter.typeError( + _functionCall.location(), ssl, + "Explicit type conversion not allowed from non-payable \"address\" to \"" + + resultType->toString() + + "\", which has a payable fallback function." + ); + } + else + m_errorReporter.typeError( + _functionCall.location(), + "Explicit type conversion not allowed from \"" + + argType->toString() + + "\" to \"" + + resultType->toString() + + "\"." + ); + } + if (resultType->category() == Type::Category::Address) + { + bool payable = true; + if (auto const* contractType = dynamic_cast<ContractType const*>(argType.get())) + payable = contractType->isPayable(); + resultType = make_shared<AddressType>(payable ? StateMutability::Payable : StateMutability::NonPayable); + } } _functionCall.annotation().type = resultType; _functionCall.annotation().isPure = isPure; @@ -2103,7 +2131,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) "after argument-dependent lookup in " + exprType->toString() + (memberName == "value" ? " - did you forget the \"payable\" modifier?" : "."); if (exprType->category() == Type::Category::Contract) - for (auto const& addressMember: AddressType().nativeMembers(nullptr)) + for (auto const& addressMember: AddressType(StateMutability::Payable).nativeMembers(nullptr)) if (addressMember.name == memberName) { Identifier const* var = dynamic_cast<Identifier const*>(&_memberAccess.expression()); @@ -2354,7 +2382,7 @@ void TypeChecker::endVisit(Literal const& _literal) if (_literal.looksLikeAddress()) { // Assign type here if it even looks like an address. This prevents double errors for invalid addresses - _literal.annotation().type = make_shared<AddressType>(); + _literal.annotation().type = make_shared<AddressType>(StateMutability::Payable); string msg; if (_literal.value().length() != 42) // "0x" + 40 hex digits diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index beab356c..8d52851a 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -394,10 +394,15 @@ bool ASTJsonConverter::visit(EventDefinition const& _node) bool ASTJsonConverter::visit(ElementaryTypeName const& _node) { - setJsonNode(_node, "ElementaryTypeName", { + std::vector<pair<string, Json::Value>> attributes = { make_pair("name", _node.typeName().toString()), make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true)) - }); + }; + + if (_node.stateMutability()) + attributes.emplace_back(make_pair("stateMutability", stateMutabilityToString(*_node.stateMutability()))); + + setJsonNode(_node, "ElementaryTypeName", std::move(attributes)); return false; } diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index a302203b..25702f19 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -299,7 +299,7 @@ TypePointer Type::fromElementaryTypeName(ElementaryTypeNameToken const& _type) case Token::Byte: return make_shared<FixedBytesType>(1); case Token::Address: - return make_shared<AddressType>(); + return make_shared<AddressType>(StateMutability::NonPayable); case Token::Bool: return make_shared<BoolType>(); case Token::Bytes: @@ -340,6 +340,17 @@ TypePointer Type::fromElementaryTypeName(string const& _name) } return ref->copyForLocation(location, true); } + else if (t->category() == Type::Category::Address) + { + if (nameParts.size() == 2) + { + if (nameParts[1] == "payable") + return make_shared<AddressType>(StateMutability::Payable); + else + solAssert(false, "Invalid state mutability for address type: " + nameParts[1]); + } + return make_shared<AddressType>(StateMutability::NonPayable); + } else { solAssert(nameParts.size() == 1, "Storage location suffix only allowed for reference types"); @@ -439,21 +450,48 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition return members; } +AddressType::AddressType(StateMutability _stateMutability): + m_stateMutability(_stateMutability) +{ + solAssert(m_stateMutability == StateMutability::Payable || m_stateMutability == StateMutability::NonPayable, ""); +} + string AddressType::richIdentifier() const { - return "t_address"; + if (m_stateMutability == StateMutability::Payable) + return "t_address_payable"; + else + return "t_address"; +} + +bool AddressType::isImplicitlyConvertibleTo(Type const& _other) const +{ + if (_other.category() != category()) + return false; + AddressType const& other = dynamic_cast<AddressType const&>(_other); + + return other.m_stateMutability <= m_stateMutability; } bool AddressType::isExplicitlyConvertibleTo(Type const& _convertTo) const { + if (auto const* contractType = dynamic_cast<ContractType const*>(&_convertTo)) + return (m_stateMutability >= StateMutability::Payable) || !contractType->isPayable(); return isImplicitlyConvertibleTo(_convertTo) || - _convertTo.category() == Category::Contract || _convertTo.category() == Category::Integer || (_convertTo.category() == Category::FixedBytes && 160 == dynamic_cast<FixedBytesType const&>(_convertTo).numBytes() * 8); } string AddressType::toString(bool) const { + if (m_stateMutability == StateMutability::Payable) + return "address payable"; + else + return "address"; +} + +string AddressType::canonicalName() const +{ return "address"; } @@ -479,17 +517,29 @@ TypePointer AddressType::binaryOperatorResult(Token::Value _operator, TypePointe return Type::commonType(shared_from_this(), _other); } +bool AddressType::operator==(Type const& _other) const +{ + if (_other.category() != category()) + return false; + AddressType const& other = dynamic_cast<AddressType const&>(_other); + return other.m_stateMutability == m_stateMutability; +} + MemberList::MemberMap AddressType::nativeMembers(ContractDefinition const*) const { - return { + MemberList::MemberMap members = { {"balance", make_shared<IntegerType>(256)}, {"call", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCall, false, StateMutability::Payable)}, {"callcode", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCallCode, false, StateMutability::Payable)}, {"delegatecall", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareDelegateCall, false)}, - {"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send)}, - {"staticcall", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareStaticCall, false, StateMutability::View)}, - {"transfer", make_shared<FunctionType>(strings{"uint"}, strings(), FunctionType::Kind::Transfer)} + {"staticcall", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareStaticCall, false, StateMutability::View)} }; + if (m_stateMutability == StateMutability::Payable) + { + members.emplace_back(MemberList::Member{"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send)}); + members.emplace_back(MemberList::Member{"transfer", make_shared<FunctionType>(strings{"uint"}, strings(), FunctionType::Kind::Transfer)}); + } + return members; } namespace @@ -1476,7 +1526,9 @@ bool ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const bool ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const { - return isImplicitlyConvertibleTo(_convertTo) || _convertTo.category() == Category::Address; + if (auto const* addressType = dynamic_cast<AddressType const*>(&_convertTo)) + return isPayable() || (addressType->stateMutability() < StateMutability::Payable); + return isImplicitlyConvertibleTo(_convertTo); } bool ContractType::isPayable() const @@ -3275,7 +3327,7 @@ MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const { case Kind::Block: return MemberList::MemberMap({ - {"coinbase", make_shared<AddressType>()}, + {"coinbase", make_shared<AddressType>(StateMutability::Payable)}, {"timestamp", make_shared<IntegerType>(256)}, {"blockhash", make_shared<FunctionType>(strings{"uint"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)}, {"difficulty", make_shared<IntegerType>(256)}, @@ -3284,7 +3336,7 @@ MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const }); case Kind::Message: return MemberList::MemberMap({ - {"sender", make_shared<AddressType>()}, + {"sender", make_shared<AddressType>(StateMutability::Payable)}, {"gas", make_shared<IntegerType>(256)}, {"value", make_shared<IntegerType>(256)}, {"data", make_shared<ArrayType>(DataLocation::CallData)}, @@ -3292,7 +3344,7 @@ MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const }); case Kind::Transaction: return MemberList::MemberMap({ - {"origin", make_shared<AddressType>()}, + {"origin", make_shared<AddressType>(StateMutability::Payable)}, {"gasprice", make_shared<IntegerType>(256)} }); case Kind::ABI: diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 7ee66838..a2d18b0a 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -321,15 +321,16 @@ class AddressType: public Type public: virtual Category category() const override { return Category::Address; } - explicit AddressType() - { - } + explicit AddressType(StateMutability _stateMutability); virtual std::string richIdentifier() const override; + virtual bool isImplicitlyConvertibleTo(Type const& _other) const override; virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override; + virtual bool operator==(Type const& _other) const override; + virtual unsigned calldataEncodedSize(bool _padded = true) const override { return _padded ? 32 : 160 / 8; } virtual unsigned storageBytes() const override { return 160 / 8; } virtual bool isValueType() const override { return true; } @@ -337,11 +338,17 @@ public: virtual MemberList::MemberMap nativeMembers(ContractDefinition const*) const override; virtual std::string toString(bool _short) const override; + virtual std::string canonicalName() const override; virtual u256 literalValue(Literal const* _literal) const override; virtual TypePointer encodingType() const override { return shared_from_this(); } virtual TypePointer interfaceType(bool) const override { return shared_from_this(); } + + StateMutability stateMutability(void) const { return m_stateMutability; } + +private: + StateMutability m_stateMutability; }; /** @@ -755,7 +762,7 @@ public: { if (isSuper()) return TypePointer{}; - return std::make_shared<AddressType>(); + return std::make_shared<AddressType>(isPayable() ? StateMutability::Payable : StateMutability::NonPayable); } virtual TypePointer interfaceType(bool _inLibrary) const override { diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index 5e5fe84a..6c27533c 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -242,8 +242,14 @@ string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure) break; } case Type::Category::Contract: - templ("body", "cleaned := " + cleanupFunction(AddressType()) + "(value)"); + { + AddressType addressType(dynamic_cast<ContractType const&>(_type).isPayable() ? + StateMutability::Payable : + StateMutability::NonPayable + ); + templ("body", "cleaned := " + cleanupFunction(addressType) + "(value)"); break; + } case Type::Category::Enum: { size_t members = dynamic_cast<EnumType const&>(_type).numberOfMembers(); diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 45e58bd0..bd863e05 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1259,7 +1259,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) identifier = FunctionType(*function).externalIdentifier(); else solAssert(false, "Contract member is neither variable nor function."); - utils().convertType(type, AddressType(), true); + utils().convertType(type, AddressType(type.isPayable() ? StateMutability::Payable : StateMutability::NonPayable), true); m_context << identifier; } else @@ -1277,15 +1277,24 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) { utils().convertType( *_memberAccess.expression().annotation().type, - AddressType(), + AddressType(StateMutability::NonPayable), true ); m_context << Instruction::BALANCE; } - else if ((set<string>{"send", "transfer", "call", "callcode", "delegatecall", "staticcall"}).count(member)) + else if ((set<string>{"send", "transfer"}).count(member)) + { + solAssert(dynamic_cast<AddressType const&>(*_memberAccess.expression().annotation().type).stateMutability() == StateMutability::Payable, ""); + utils().convertType( + *_memberAccess.expression().annotation().type, + AddressType(StateMutability::Payable), + true + ); + } + else if ((set<string>{"call", "callcode", "delegatecall", "staticcall"}).count(member)) utils().convertType( *_memberAccess.expression().annotation().type, - AddressType(), + AddressType(StateMutability::NonPayable), true ); else diff --git a/test/libsolidity/ASTJSON/address_payable.json b/test/libsolidity/ASTJSON/address_payable.json new file mode 100644 index 00000000..42ad33e5 --- /dev/null +++ b/test/libsolidity/ASTJSON/address_payable.json @@ -0,0 +1,560 @@ +{ + "absolutePath" : "a", + "exportedSymbols" : + { + "C" : + [ + 37 + ] + }, + "id" : 38, + "nodeType" : "SourceUnit", + "nodes" : + [ + { + "baseContracts" : [], + "contractDependencies" : [], + "contractKind" : "contract", + "documentation" : null, + "fullyImplemented" : true, + "id" : 37, + "linearizedBaseContracts" : + [ + 37 + ], + "name" : "C", + "nodeType" : "ContractDefinition", + "nodes" : + [ + { + "constant" : false, + "id" : 4, + "name" : "m", + "nodeType" : "VariableDeclaration", + "scope" : 37, + "src" : "17:44:1", + "stateVariable" : true, + "storageLocation" : "default", + "typeDescriptions" : + { + "typeIdentifier" : "t_mapping$_t_address_$_t_address_payable_$", + "typeString" : "mapping(address => address payable)" + }, + "typeName" : + { + "id" : 3, + "keyType" : + { + "id" : 1, + "name" : "address", + "nodeType" : "ElementaryTypeName", + "src" : "25:7:1", + "typeDescriptions" : + { + "typeIdentifier" : "t_address", + "typeString" : "address" + } + }, + "nodeType" : "Mapping", + "src" : "17:35:1", + "typeDescriptions" : + { + "typeIdentifier" : "t_mapping$_t_address_$_t_address_payable_$", + "typeString" : "mapping(address => address payable)" + }, + "valueType" : + { + "id" : 2, + "name" : "address", + "nodeType" : "ElementaryTypeName", + "src" : "36:15:1", + "stateMutability" : "payable", + "typeDescriptions" : + { + "typeIdentifier" : "t_address_payable", + "typeString" : "address payable" + } + } + }, + "value" : null, + "visibility" : "public" + }, + { + "body" : + { + "id" : 35, + "nodeType" : "Block", + "src" : "134:122:1", + "statements" : + [ + { + "assignments" : + [ + 12 + ], + "declarations" : + [ + { + "constant" : false, + "id" : 12, + "name" : "a", + "nodeType" : "VariableDeclaration", + "scope" : 35, + "src" : "144:17:1", + "stateVariable" : false, + "storageLocation" : "default", + "typeDescriptions" : + { + "typeIdentifier" : "t_address_payable", + "typeString" : "address payable" + }, + "typeName" : + { + "id" : 11, + "name" : "address", + "nodeType" : "ElementaryTypeName", + "src" : "144:15:1", + "stateMutability" : "payable", + "typeDescriptions" : + { + "typeIdentifier" : "t_address_payable", + "typeString" : "address payable" + } + }, + "value" : null, + "visibility" : "internal" + } + ], + "id" : 16, + "initialValue" : + { + "argumentTypes" : null, + "baseExpression" : + { + "argumentTypes" : null, + "id" : 13, + "name" : "m", + "nodeType" : "Identifier", + "overloadedDeclarations" : [], + "referencedDeclaration" : 4, + "src" : "164:1:1", + "typeDescriptions" : + { + "typeIdentifier" : "t_mapping$_t_address_$_t_address_payable_$", + "typeString" : "mapping(address => address payable)" + } + }, + "id" : 15, + "indexExpression" : + { + "argumentTypes" : null, + "id" : 14, + "name" : "arg", + "nodeType" : "Identifier", + "overloadedDeclarations" : [], + "referencedDeclaration" : 6, + "src" : "166:3:1", + "typeDescriptions" : + { + "typeIdentifier" : "t_address_payable", + "typeString" : "address payable" + } + }, + "isConstant" : false, + "isLValue" : true, + "isPure" : false, + "lValueRequested" : false, + "nodeType" : "IndexAccess", + "src" : "164:6:1", + "typeDescriptions" : + { + "typeIdentifier" : "t_address_payable", + "typeString" : "address payable" + } + }, + "nodeType" : "VariableDeclarationStatement", + "src" : "144:26:1" + }, + { + "expression" : + { + "argumentTypes" : null, + "id" : 19, + "isConstant" : false, + "isLValue" : false, + "isPure" : false, + "lValueRequested" : false, + "leftHandSide" : + { + "argumentTypes" : null, + "id" : 17, + "name" : "r", + "nodeType" : "Identifier", + "overloadedDeclarations" : [], + "referencedDeclaration" : 9, + "src" : "180:1:1", + "typeDescriptions" : + { + "typeIdentifier" : "t_address_payable", + "typeString" : "address payable" + } + }, + "nodeType" : "Assignment", + "operator" : "=", + "rightHandSide" : + { + "argumentTypes" : null, + "id" : 18, + "name" : "arg", + "nodeType" : "Identifier", + "overloadedDeclarations" : [], + "referencedDeclaration" : 6, + "src" : "184:3:1", + "typeDescriptions" : + { + "typeIdentifier" : "t_address_payable", + "typeString" : "address payable" + } + }, + "src" : "180:7:1", + "typeDescriptions" : + { + "typeIdentifier" : "t_address_payable", + "typeString" : "address payable" + } + }, + "id" : 20, + "nodeType" : "ExpressionStatement", + "src" : "180:7:1" + }, + { + "assignments" : + [ + 22 + ], + "declarations" : + [ + { + "constant" : false, + "id" : 22, + "name" : "c", + "nodeType" : "VariableDeclaration", + "scope" : 35, + "src" : "197:9:1", + "stateVariable" : false, + "storageLocation" : "default", + "typeDescriptions" : + { + "typeIdentifier" : "t_address", + "typeString" : "address" + }, + "typeName" : + { + "id" : 21, + "name" : "address", + "nodeType" : "ElementaryTypeName", + "src" : "197:7:1", + "stateMutability" : "nonpayable", + "typeDescriptions" : + { + "typeIdentifier" : "t_address", + "typeString" : "address" + } + }, + "value" : null, + "visibility" : "internal" + } + ], + "id" : 26, + "initialValue" : + { + "argumentTypes" : null, + "arguments" : + [ + { + "argumentTypes" : null, + "id" : 24, + "name" : "this", + "nodeType" : "Identifier", + "overloadedDeclarations" : [], + "referencedDeclaration" : 65, + "src" : "217:4:1", + "typeDescriptions" : + { + "typeIdentifier" : "t_contract$_C_$37", + "typeString" : "contract C" + } + } + ], + "expression" : + { + "argumentTypes" : + [ + { + "typeIdentifier" : "t_contract$_C_$37", + "typeString" : "contract C" + } + ], + "id" : 23, + "isConstant" : false, + "isLValue" : false, + "isPure" : true, + "lValueRequested" : false, + "nodeType" : "ElementaryTypeNameExpression", + "src" : "209:7:1", + "typeDescriptions" : + { + "typeIdentifier" : "t_type$_t_address_$", + "typeString" : "type(address)" + }, + "typeName" : "address" + }, + "id" : 25, + "isConstant" : false, + "isLValue" : false, + "isPure" : false, + "kind" : "typeConversion", + "lValueRequested" : false, + "names" : [], + "nodeType" : "FunctionCall", + "src" : "209:13:1", + "typeDescriptions" : + { + "typeIdentifier" : "t_address", + "typeString" : "address" + } + }, + "nodeType" : "VariableDeclarationStatement", + "src" : "197:25:1" + }, + { + "expression" : + { + "argumentTypes" : null, + "id" : 33, + "isConstant" : false, + "isLValue" : false, + "isPure" : false, + "lValueRequested" : false, + "leftHandSide" : + { + "argumentTypes" : null, + "baseExpression" : + { + "argumentTypes" : null, + "id" : 27, + "name" : "m", + "nodeType" : "Identifier", + "overloadedDeclarations" : [], + "referencedDeclaration" : 4, + "src" : "232:1:1", + "typeDescriptions" : + { + "typeIdentifier" : "t_mapping$_t_address_$_t_address_payable_$", + "typeString" : "mapping(address => address payable)" + } + }, + "id" : 29, + "indexExpression" : + { + "argumentTypes" : null, + "id" : 28, + "name" : "c", + "nodeType" : "Identifier", + "overloadedDeclarations" : [], + "referencedDeclaration" : 22, + "src" : "234:1:1", + "typeDescriptions" : + { + "typeIdentifier" : "t_address", + "typeString" : "address" + } + }, + "isConstant" : false, + "isLValue" : true, + "isPure" : false, + "lValueRequested" : true, + "nodeType" : "IndexAccess", + "src" : "232:4:1", + "typeDescriptions" : + { + "typeIdentifier" : "t_address_payable", + "typeString" : "address payable" + } + }, + "nodeType" : "Assignment", + "operator" : "=", + "rightHandSide" : + { + "argumentTypes" : null, + "arguments" : + [ + { + "argumentTypes" : null, + "hexValue" : "30", + "id" : 31, + "isConstant" : false, + "isLValue" : false, + "isPure" : true, + "kind" : "number", + "lValueRequested" : false, + "nodeType" : "Literal", + "src" : "247:1:1", + "subdenomination" : null, + "typeDescriptions" : + { + "typeIdentifier" : "t_rational_0_by_1", + "typeString" : "int_const 0" + }, + "value" : "0" + } + ], + "expression" : + { + "argumentTypes" : + [ + { + "typeIdentifier" : "t_rational_0_by_1", + "typeString" : "int_const 0" + } + ], + "id" : 30, + "isConstant" : false, + "isLValue" : false, + "isPure" : true, + "lValueRequested" : false, + "nodeType" : "ElementaryTypeNameExpression", + "src" : "239:7:1", + "typeDescriptions" : + { + "typeIdentifier" : "t_type$_t_address_$", + "typeString" : "type(address)" + }, + "typeName" : "address" + }, + "id" : 32, + "isConstant" : false, + "isLValue" : false, + "isPure" : true, + "kind" : "typeConversion", + "lValueRequested" : false, + "names" : [], + "nodeType" : "FunctionCall", + "src" : "239:10:1", + "typeDescriptions" : + { + "typeIdentifier" : "t_address_payable", + "typeString" : "address payable" + } + }, + "src" : "232:17:1", + "typeDescriptions" : + { + "typeIdentifier" : "t_address_payable", + "typeString" : "address payable" + } + }, + "id" : 34, + "nodeType" : "ExpressionStatement", + "src" : "232:17:1" + } + ] + }, + "documentation" : null, + "id" : 36, + "implemented" : true, + "isConstructor" : false, + "modifiers" : [], + "name" : "f", + "nodeType" : "FunctionDefinition", + "parameters" : + { + "id" : 7, + "nodeType" : "ParameterList", + "parameters" : + [ + { + "constant" : false, + "id" : 6, + "name" : "arg", + "nodeType" : "VariableDeclaration", + "scope" : 36, + "src" : "78:19:1", + "stateVariable" : false, + "storageLocation" : "default", + "typeDescriptions" : + { + "typeIdentifier" : "t_address_payable", + "typeString" : "address payable" + }, + "typeName" : + { + "id" : 5, + "name" : "address", + "nodeType" : "ElementaryTypeName", + "src" : "78:15:1", + "stateMutability" : "payable", + "typeDescriptions" : + { + "typeIdentifier" : "t_address_payable", + "typeString" : "address payable" + } + }, + "value" : null, + "visibility" : "internal" + } + ], + "src" : "77:21:1" + }, + "returnParameters" : + { + "id" : 10, + "nodeType" : "ParameterList", + "parameters" : + [ + { + "constant" : false, + "id" : 9, + "name" : "r", + "nodeType" : "VariableDeclaration", + "scope" : 36, + "src" : "115:17:1", + "stateVariable" : false, + "storageLocation" : "default", + "typeDescriptions" : + { + "typeIdentifier" : "t_address_payable", + "typeString" : "address payable" + }, + "typeName" : + { + "id" : 8, + "name" : "address", + "nodeType" : "ElementaryTypeName", + "src" : "115:15:1", + "stateMutability" : "payable", + "typeDescriptions" : + { + "typeIdentifier" : "t_address_payable", + "typeString" : "address payable" + } + }, + "value" : null, + "visibility" : "internal" + } + ], + "src" : "114:19:1" + }, + "scope" : 37, + "src" : "67:189:1", + "stateMutability" : "nonpayable", + "superFunction" : null, + "visibility" : "public" + } + ], + "scope" : 38, + "src" : "0:258:1" + } + ], + "src" : "0:259:1" +} diff --git a/test/libsolidity/ASTJSON/address_payable.sol b/test/libsolidity/ASTJSON/address_payable.sol new file mode 100644 index 00000000..f7cc66cb --- /dev/null +++ b/test/libsolidity/ASTJSON/address_payable.sol @@ -0,0 +1,11 @@ +contract C { + mapping(address => address payable) public m; + function f(address payable arg) public returns (address payable r) { + address payable a = m[arg]; + r = arg; + address c = address(this); + m[c] = address(0); + } +} + +// ---- diff --git a/test/libsolidity/ASTJSON/address_payable_legacy.json b/test/libsolidity/ASTJSON/address_payable_legacy.json new file mode 100644 index 00000000..11a634c3 --- /dev/null +++ b/test/libsolidity/ASTJSON/address_payable_legacy.json @@ -0,0 +1,600 @@ +{ + "attributes" : + { + "absolutePath" : "a", + "exportedSymbols" : + { + "C" : + [ + 37 + ] + } + }, + "children" : + [ + { + "attributes" : + { + "baseContracts" : + [ + null + ], + "contractDependencies" : + [ + null + ], + "contractKind" : "contract", + "documentation" : null, + "fullyImplemented" : true, + "linearizedBaseContracts" : + [ + 37 + ], + "name" : "C", + "scope" : 38 + }, + "children" : + [ + { + "attributes" : + { + "constant" : false, + "name" : "m", + "scope" : 37, + "stateVariable" : true, + "storageLocation" : "default", + "type" : "mapping(address => address payable)", + "value" : null, + "visibility" : "public" + }, + "children" : + [ + { + "attributes" : + { + "type" : "mapping(address => address payable)" + }, + "children" : + [ + { + "attributes" : + { + "name" : "address", + "type" : "address" + }, + "id" : 1, + "name" : "ElementaryTypeName", + "src" : "25:7:1" + }, + { + "attributes" : + { + "name" : "address", + "stateMutability" : "payable", + "type" : "address payable" + }, + "id" : 2, + "name" : "ElementaryTypeName", + "src" : "36:15:1" + } + ], + "id" : 3, + "name" : "Mapping", + "src" : "17:35:1" + } + ], + "id" : 4, + "name" : "VariableDeclaration", + "src" : "17:44:1" + }, + { + "attributes" : + { + "documentation" : null, + "implemented" : true, + "isConstructor" : false, + "modifiers" : + [ + null + ], + "name" : "f", + "scope" : 37, + "stateMutability" : "nonpayable", + "superFunction" : null, + "visibility" : "public" + }, + "children" : + [ + { + "children" : + [ + { + "attributes" : + { + "constant" : false, + "name" : "arg", + "scope" : 36, + "stateVariable" : false, + "storageLocation" : "default", + "type" : "address payable", + "value" : null, + "visibility" : "internal" + }, + "children" : + [ + { + "attributes" : + { + "name" : "address", + "stateMutability" : "payable", + "type" : "address payable" + }, + "id" : 5, + "name" : "ElementaryTypeName", + "src" : "78:15:1" + } + ], + "id" : 6, + "name" : "VariableDeclaration", + "src" : "78:19:1" + } + ], + "id" : 7, + "name" : "ParameterList", + "src" : "77:21:1" + }, + { + "children" : + [ + { + "attributes" : + { + "constant" : false, + "name" : "r", + "scope" : 36, + "stateVariable" : false, + "storageLocation" : "default", + "type" : "address payable", + "value" : null, + "visibility" : "internal" + }, + "children" : + [ + { + "attributes" : + { + "name" : "address", + "stateMutability" : "payable", + "type" : "address payable" + }, + "id" : 8, + "name" : "ElementaryTypeName", + "src" : "115:15:1" + } + ], + "id" : 9, + "name" : "VariableDeclaration", + "src" : "115:17:1" + } + ], + "id" : 10, + "name" : "ParameterList", + "src" : "114:19:1" + }, + { + "children" : + [ + { + "attributes" : + { + "assignments" : + [ + 12 + ] + }, + "children" : + [ + { + "attributes" : + { + "constant" : false, + "name" : "a", + "scope" : 35, + "stateVariable" : false, + "storageLocation" : "default", + "type" : "address payable", + "value" : null, + "visibility" : "internal" + }, + "children" : + [ + { + "attributes" : + { + "name" : "address", + "stateMutability" : "payable", + "type" : "address payable" + }, + "id" : 11, + "name" : "ElementaryTypeName", + "src" : "144:15:1" + } + ], + "id" : 12, + "name" : "VariableDeclaration", + "src" : "144:17:1" + }, + { + "attributes" : + { + "argumentTypes" : null, + "isConstant" : false, + "isLValue" : true, + "isPure" : false, + "lValueRequested" : false, + "type" : "address payable" + }, + "children" : + [ + { + "attributes" : + { + "argumentTypes" : null, + "overloadedDeclarations" : + [ + null + ], + "referencedDeclaration" : 4, + "type" : "mapping(address => address payable)", + "value" : "m" + }, + "id" : 13, + "name" : "Identifier", + "src" : "164:1:1" + }, + { + "attributes" : + { + "argumentTypes" : null, + "overloadedDeclarations" : + [ + null + ], + "referencedDeclaration" : 6, + "type" : "address payable", + "value" : "arg" + }, + "id" : 14, + "name" : "Identifier", + "src" : "166:3:1" + } + ], + "id" : 15, + "name" : "IndexAccess", + "src" : "164:6:1" + } + ], + "id" : 16, + "name" : "VariableDeclarationStatement", + "src" : "144:26:1" + }, + { + "children" : + [ + { + "attributes" : + { + "argumentTypes" : null, + "isConstant" : false, + "isLValue" : false, + "isPure" : false, + "lValueRequested" : false, + "operator" : "=", + "type" : "address payable" + }, + "children" : + [ + { + "attributes" : + { + "argumentTypes" : null, + "overloadedDeclarations" : + [ + null + ], + "referencedDeclaration" : 9, + "type" : "address payable", + "value" : "r" + }, + "id" : 17, + "name" : "Identifier", + "src" : "180:1:1" + }, + { + "attributes" : + { + "argumentTypes" : null, + "overloadedDeclarations" : + [ + null + ], + "referencedDeclaration" : 6, + "type" : "address payable", + "value" : "arg" + }, + "id" : 18, + "name" : "Identifier", + "src" : "184:3:1" + } + ], + "id" : 19, + "name" : "Assignment", + "src" : "180:7:1" + } + ], + "id" : 20, + "name" : "ExpressionStatement", + "src" : "180:7:1" + }, + { + "attributes" : + { + "assignments" : + [ + 22 + ] + }, + "children" : + [ + { + "attributes" : + { + "constant" : false, + "name" : "c", + "scope" : 35, + "stateVariable" : false, + "storageLocation" : "default", + "type" : "address", + "value" : null, + "visibility" : "internal" + }, + "children" : + [ + { + "attributes" : + { + "name" : "address", + "stateMutability" : "nonpayable", + "type" : "address" + }, + "id" : 21, + "name" : "ElementaryTypeName", + "src" : "197:7:1" + } + ], + "id" : 22, + "name" : "VariableDeclaration", + "src" : "197:9:1" + }, + { + "attributes" : + { + "argumentTypes" : null, + "isConstant" : false, + "isLValue" : false, + "isPure" : false, + "isStructConstructorCall" : false, + "lValueRequested" : false, + "names" : + [ + null + ], + "type" : "address", + "type_conversion" : true + }, + "children" : + [ + { + "attributes" : + { + "argumentTypes" : + [ + { + "typeIdentifier" : "t_contract$_C_$37", + "typeString" : "contract C" + } + ], + "isConstant" : false, + "isLValue" : false, + "isPure" : true, + "lValueRequested" : false, + "type" : "type(address)", + "value" : "address" + }, + "id" : 23, + "name" : "ElementaryTypeNameExpression", + "src" : "209:7:1" + }, + { + "attributes" : + { + "argumentTypes" : null, + "overloadedDeclarations" : + [ + null + ], + "referencedDeclaration" : 65, + "type" : "contract C", + "value" : "this" + }, + "id" : 24, + "name" : "Identifier", + "src" : "217:4:1" + } + ], + "id" : 25, + "name" : "FunctionCall", + "src" : "209:13:1" + } + ], + "id" : 26, + "name" : "VariableDeclarationStatement", + "src" : "197:25:1" + }, + { + "children" : + [ + { + "attributes" : + { + "argumentTypes" : null, + "isConstant" : false, + "isLValue" : false, + "isPure" : false, + "lValueRequested" : false, + "operator" : "=", + "type" : "address payable" + }, + "children" : + [ + { + "attributes" : + { + "argumentTypes" : null, + "isConstant" : false, + "isLValue" : true, + "isPure" : false, + "lValueRequested" : true, + "type" : "address payable" + }, + "children" : + [ + { + "attributes" : + { + "argumentTypes" : null, + "overloadedDeclarations" : + [ + null + ], + "referencedDeclaration" : 4, + "type" : "mapping(address => address payable)", + "value" : "m" + }, + "id" : 27, + "name" : "Identifier", + "src" : "232:1:1" + }, + { + "attributes" : + { + "argumentTypes" : null, + "overloadedDeclarations" : + [ + null + ], + "referencedDeclaration" : 22, + "type" : "address", + "value" : "c" + }, + "id" : 28, + "name" : "Identifier", + "src" : "234:1:1" + } + ], + "id" : 29, + "name" : "IndexAccess", + "src" : "232:4:1" + }, + { + "attributes" : + { + "argumentTypes" : null, + "isConstant" : false, + "isLValue" : false, + "isPure" : true, + "isStructConstructorCall" : false, + "lValueRequested" : false, + "names" : + [ + null + ], + "type" : "address payable", + "type_conversion" : true + }, + "children" : + [ + { + "attributes" : + { + "argumentTypes" : + [ + { + "typeIdentifier" : "t_rational_0_by_1", + "typeString" : "int_const 0" + } + ], + "isConstant" : false, + "isLValue" : false, + "isPure" : true, + "lValueRequested" : false, + "type" : "type(address)", + "value" : "address" + }, + "id" : 30, + "name" : "ElementaryTypeNameExpression", + "src" : "239:7:1" + }, + { + "attributes" : + { + "argumentTypes" : null, + "hexvalue" : "30", + "isConstant" : false, + "isLValue" : false, + "isPure" : true, + "lValueRequested" : false, + "subdenomination" : null, + "token" : "number", + "type" : "int_const 0", + "value" : "0" + }, + "id" : 31, + "name" : "Literal", + "src" : "247:1:1" + } + ], + "id" : 32, + "name" : "FunctionCall", + "src" : "239:10:1" + } + ], + "id" : 33, + "name" : "Assignment", + "src" : "232:17:1" + } + ], + "id" : 34, + "name" : "ExpressionStatement", + "src" : "232:17:1" + } + ], + "id" : 35, + "name" : "Block", + "src" : "134:122:1" + } + ], + "id" : 36, + "name" : "FunctionDefinition", + "src" : "67:189:1" + } + ], + "id" : 37, + "name" : "ContractDefinition", + "src" : "0:258:1" + } + ], + "id" : 38, + "name" : "SourceUnit", + "src" : "0:259:1" +} diff --git a/test/libsolidity/syntaxTests/parsing/address_in_struct.sol b/test/libsolidity/syntaxTests/parsing/address_in_struct.sol new file mode 100644 index 00000000..68049b50 --- /dev/null +++ b/test/libsolidity/syntaxTests/parsing/address_in_struct.sol @@ -0,0 +1,6 @@ +contract C { + struct S { + address payable a; + address b; + } +} diff --git a/test/libsolidity/syntaxTests/parsing/address_nonpayable.sol b/test/libsolidity/syntaxTests/parsing/address_nonpayable.sol new file mode 100644 index 00000000..fea67138 --- /dev/null +++ b/test/libsolidity/syntaxTests/parsing/address_nonpayable.sol @@ -0,0 +1,7 @@ +contract C { + address a; + function f(address b) public pure returns (address c) { + address d = b; + return d; + } +} diff --git a/test/libsolidity/syntaxTests/parsing/address_payable.sol b/test/libsolidity/syntaxTests/parsing/address_payable.sol new file mode 100644 index 00000000..c29ae1b7 --- /dev/null +++ b/test/libsolidity/syntaxTests/parsing/address_payable.sol @@ -0,0 +1,7 @@ +contract C { + address payable a; + function f(address payable b) public pure returns (address payable c) { + address payable d = b; + return d; + } +} diff --git a/test/libsolidity/syntaxTests/types/address/address_abi_decode.sol b/test/libsolidity/syntaxTests/types/address/address_abi_decode.sol new file mode 100644 index 00000000..7be61ad2 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/address_abi_decode.sol @@ -0,0 +1,6 @@ +contract C { + function f(bytes memory b) public pure returns (address payable) { + (address payable c) = abi.decode(b, (address)); + return c; + } +}
\ No newline at end of file diff --git a/test/libsolidity/syntaxTests/types/address/address_constant.sol b/test/libsolidity/syntaxTests/types/address/address_constant.sol new file mode 100644 index 00000000..0b1af991 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/address_constant.sol @@ -0,0 +1,7 @@ +contract C { + address constant a = address(0); + address payable constant b = address(0); + function f() public pure returns (address, address) { + return (a,b); + } +} diff --git a/test/libsolidity/syntaxTests/types/address/address_constant_assignment.sol b/test/libsolidity/syntaxTests/types/address/address_constant_assignment.sol new file mode 100644 index 00000000..da17ae33 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/address_constant_assignment.sol @@ -0,0 +1,11 @@ +contract C { + address constant a = address(0); + address payable constant b = address(0); + function f() public { + a = address(0); + b = address(0); + } +} +// ---- +// TypeError: (129-130): Cannot assign to a constant variable. +// TypeError: (153-154): Cannot assign to a constant variable. diff --git a/test/libsolidity/syntaxTests/types/address/address_in_struct_fail.sol b/test/libsolidity/syntaxTests/types/address/address_in_struct_fail.sol new file mode 100644 index 00000000..9a5b2abb --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/address_in_struct_fail.sol @@ -0,0 +1,11 @@ +contract A { + struct S { + address payable a; + } + S s; + function f() public { + s.a = address(this); + } +} +// ---- +// TypeError: (110-123): Type address is not implicitly convertible to expected type address payable. diff --git a/test/libsolidity/syntaxTests/types/address/address_in_struct_fine.sol b/test/libsolidity/syntaxTests/types/address/address_in_struct_fine.sol new file mode 100644 index 00000000..5519f0ef --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/address_in_struct_fine.sol @@ -0,0 +1,20 @@ +contract A { + struct S { + address a; + } + S s; + function f() public { + s.a = address(this); + } +} +contract B { + struct S { + address payable a; + } + S s; + function f() public { + s.a = address(this); + } + function() external payable { + } +}
\ No newline at end of file diff --git a/test/libsolidity/syntaxTests/types/address/address_nonpayable_selfdestruct.sol b/test/libsolidity/syntaxTests/types/address/address_nonpayable_selfdestruct.sol new file mode 100644 index 00000000..cc680ff3 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/address_nonpayable_selfdestruct.sol @@ -0,0 +1,7 @@ +contract C { + function f(address a) public { + selfdestruct(a); + } +} +// ---- +// TypeError: (69-70): Invalid type for argument in function call. Invalid implicit conversion from address to address payable requested. diff --git a/test/libsolidity/syntaxTests/types/address/address_payable_external_overload.sol b/test/libsolidity/syntaxTests/types/address/address_payable_external_overload.sol new file mode 100644 index 00000000..875532c4 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/address_payable_external_overload.sol @@ -0,0 +1,7 @@ +contract C { + function f(address) external pure {} + function f(address payable) external pure {} + +} +// ---- +// TypeError: (58-102): Function overload clash during conversion to external types for arguments. diff --git a/test/libsolidity/syntaxTests/types/address/address_payable_internal_overload_nonpayable.sol b/test/libsolidity/syntaxTests/types/address/address_payable_internal_overload_nonpayable.sol new file mode 100644 index 00000000..65600544 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/address_payable_internal_overload_nonpayable.sol @@ -0,0 +1,10 @@ +contract C { + function f(address payable) internal pure {} + function f(address) internal pure returns (uint) {} + function g() internal pure { + address a = address(0); + uint b = f(a); // TODO: should this be valid? + b; + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/types/address/address_payable_internal_overload_payable.sol b/test/libsolidity/syntaxTests/types/address/address_payable_internal_overload_payable.sol new file mode 100644 index 00000000..84142a31 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/address_payable_internal_overload_payable.sol @@ -0,0 +1,10 @@ +contract C { + function f(address payable) internal pure {} + function f(address) internal pure {} + function g() internal pure { + address payable a = address(0); + f(a); + } +} +// ---- +// TypeError: (184-185): No unique declaration found after argument-dependent lookup. diff --git a/test/libsolidity/syntaxTests/types/address/address_payable_memory_array_conversion.sol b/test/libsolidity/syntaxTests/types/address/address_payable_memory_array_conversion.sol new file mode 100644 index 00000000..ec58170b --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/address_payable_memory_array_conversion.sol @@ -0,0 +1,11 @@ +contract C { + function f() public pure { + address payable[] memory a = new address payable[](4); + address[] memory b = new address[](4); + a = b; + b = a; + } +} +// ---- +// TypeError: (166-167): Type address[] memory is not implicitly convertible to expected type address payable[] memory. +// TypeError: (181-182): Type address payable[] memory is not implicitly convertible to expected type address[] memory. diff --git a/test/libsolidity/syntaxTests/types/address/address_payable_public_overload.sol b/test/libsolidity/syntaxTests/types/address/address_payable_public_overload.sol new file mode 100644 index 00000000..839abc26 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/address_payable_public_overload.sol @@ -0,0 +1,7 @@ +contract C { + function f(address) public pure {} + function f(address payable) public pure {} + +} +// ---- +// TypeError: (56-98): Function overload clash during conversion to external types for arguments. diff --git a/test/libsolidity/syntaxTests/types/address/address_payable_selfdestruct.sol b/test/libsolidity/syntaxTests/types/address/address_payable_selfdestruct.sol new file mode 100644 index 00000000..bdf43be7 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/address_payable_selfdestruct.sol @@ -0,0 +1,5 @@ +contract C { + function f(address payable a) public { + selfdestruct(a); + } +} diff --git a/test/libsolidity/syntaxTests/types/address/address_payable_storage_array_conversion.sol b/test/libsolidity/syntaxTests/types/address/address_payable_storage_array_conversion.sol new file mode 100644 index 00000000..40f85ccc --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/address_payable_storage_array_conversion.sol @@ -0,0 +1,11 @@ +contract C { + address payable[] a; + address[] b; + function f() public view { + address payable[] storage c = a; + address[] storage d = b; + d = c; // TODO: this could be allowed in the future + } +} +// ---- +// TypeError: (172-173): Type address payable[] storage pointer is not implicitly convertible to expected type address[] storage pointer. diff --git a/test/libsolidity/syntaxTests/types/address/address_payable_storage_array_conversion_fail.sol b/test/libsolidity/syntaxTests/types/address/address_payable_storage_array_conversion_fail.sol new file mode 100644 index 00000000..3c3eb859 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/address_payable_storage_array_conversion_fail.sol @@ -0,0 +1,11 @@ +contract C { + address payable[] a; + address[] b; + function f() public view { + address payable[] storage c = a; + address[] storage d = b; + c = d; + } +} +// ---- +// TypeError: (172-173): Type address[] storage pointer is not implicitly convertible to expected type address payable[] storage pointer. diff --git a/test/libsolidity/syntaxTests/types/address/address_to_contract_implicitly.sol b/test/libsolidity/syntaxTests/types/address/address_to_contract_implicitly.sol new file mode 100644 index 00000000..c9e5ddf6 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/address_to_contract_implicitly.sol @@ -0,0 +1,7 @@ +contract C { + function f() public view { + C c = address(2); + } +} +// ---- +// TypeError: (46-62): Type address payable is not implicitly convertible to expected type contract C. diff --git a/test/libsolidity/syntaxTests/types/address/address_to_contract_payable_fallback.sol b/test/libsolidity/syntaxTests/types/address/address_to_contract_payable_fallback.sol new file mode 100644 index 00000000..6917444b --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/address_to_contract_payable_fallback.sol @@ -0,0 +1,8 @@ +contract C { + function f() public pure returns (C c) { + c = C(address(2)); + } + function() external payable { + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/types/address/address_to_payable_address.sol b/test/libsolidity/syntaxTests/types/address/address_to_payable_address.sol new file mode 100644 index 00000000..1aab9b51 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/address_to_payable_address.sol @@ -0,0 +1,10 @@ +contract C { + function f(address a) public pure { + address b; + address payable c = a; + c = b; + } +} +// ---- +// TypeError: (80-101): Type address is not implicitly convertible to expected type address payable. +// TypeError: (115-116): Type address is not implicitly convertible to expected type address payable. diff --git a/test/libsolidity/syntaxTests/types/address/address_tuple_fail.sol b/test/libsolidity/syntaxTests/types/address/address_tuple_fail.sol new file mode 100644 index 00000000..17e9e7c1 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/address_tuple_fail.sol @@ -0,0 +1,8 @@ +contract C { + function f() public view returns (address payable a, address b) { + (address c, address payable d) = (address(this), address(0)); + (a,b) = (c,d); + } +} +// ---- +// TypeError: (169-174): Type tuple(address,address payable) is not implicitly convertible to expected type tuple(address payable,address). diff --git a/test/libsolidity/syntaxTests/types/address/address_tuple_fine.sol b/test/libsolidity/syntaxTests/types/address/address_tuple_fine.sol new file mode 100644 index 00000000..846de1f4 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/address_tuple_fine.sol @@ -0,0 +1,6 @@ +contract C { + function f() public view returns (address payable a, address b) { + (address c, address payable d) = (address(this), address(0)); + (a,b) = (d,c); + } +}
\ No newline at end of file diff --git a/test/libsolidity/syntaxTests/types/address/contract_no_fallback_to_payable_address.sol b/test/libsolidity/syntaxTests/types/address/contract_no_fallback_to_payable_address.sol new file mode 100644 index 00000000..777bce00 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/contract_no_fallback_to_payable_address.sol @@ -0,0 +1,8 @@ +contract C { + function f() public view { + address payable a = address(this); + a; + } +} +// ---- +// TypeError: (46-79): Type address is not implicitly convertible to expected type address payable. diff --git a/test/libsolidity/syntaxTests/types/address/contract_non_payable_fallback_to_payable_address.sol b/test/libsolidity/syntaxTests/types/address/contract_non_payable_fallback_to_payable_address.sol new file mode 100644 index 00000000..6518eebb --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/contract_non_payable_fallback_to_payable_address.sol @@ -0,0 +1,10 @@ +contract C { + function f() public view { + address payable a = address(this); + a; + } + function() external { + } +} +// ---- +// TypeError: (46-79): Type address is not implicitly convertible to expected type address payable. diff --git a/test/libsolidity/syntaxTests/types/address/contract_payable_fallback_to_payable_address.sol b/test/libsolidity/syntaxTests/types/address/contract_payable_fallback_to_payable_address.sol new file mode 100644 index 00000000..359beeb4 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/contract_payable_fallback_to_payable_address.sol @@ -0,0 +1,9 @@ +contract C { + function f() public view { + address payable a = address(this); + a; + } + function() external payable { + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/types/address/contract_payable_fallback_to_payable_address_implicitly.sol b/test/libsolidity/syntaxTests/types/address/contract_payable_fallback_to_payable_address_implicitly.sol new file mode 100644 index 00000000..4b20b1c6 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/contract_payable_fallback_to_payable_address_implicitly.sol @@ -0,0 +1,10 @@ +contract C { + function f() public view { + address payable a = this; + a; + } + function() external payable { + } +} +// ---- +// TypeError: (46-70): Type contract C is not implicitly convertible to expected type address payable. diff --git a/test/libsolidity/syntaxTests/types/address/literal_to_address.sol b/test/libsolidity/syntaxTests/types/address/literal_to_address.sol new file mode 100644 index 00000000..9d599ea5 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/literal_to_address.sol @@ -0,0 +1,8 @@ +contract C { + function f() public pure { + address a = address(0); + a = address(1); + address b = 0x0123456789012345678901234567890123456789; + b = 0x9876543210987654321098765432109876543210; + } +} diff --git a/test/libsolidity/syntaxTests/types/address/literal_to_payable_address.sol b/test/libsolidity/syntaxTests/types/address/literal_to_payable_address.sol new file mode 100644 index 00000000..97f4d85d --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/literal_to_payable_address.sol @@ -0,0 +1,8 @@ +contract C { + function f() public pure { + address payable a = address(0); + a = address(1); + address payable b = 0x0123456789012345678901234567890123456789; + b = 0x9876543210987654321098765432109876543210; + } +}
\ No newline at end of file diff --git a/test/libsolidity/syntaxTests/types/address/nonpayable_address_to_contract_payable_fallback.sol b/test/libsolidity/syntaxTests/types/address/nonpayable_address_to_contract_payable_fallback.sol new file mode 100644 index 00000000..e13a0897 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/nonpayable_address_to_contract_payable_fallback.sol @@ -0,0 +1,10 @@ +contract C { + function f() public pure returns (C c) { + address a = address(2); + c = C(a); + } + function() external payable { + } +} +// ---- +// TypeError: (92-96): Explicit type conversion not allowed from non-payable "address" to "contract C", which has a payable fallback function. diff --git a/test/libsolidity/syntaxTests/types/address/payable_address_to_address.sol b/test/libsolidity/syntaxTests/types/address/payable_address_to_address.sol new file mode 100644 index 00000000..f5dbf937 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address/payable_address_to_address.sol @@ -0,0 +1,7 @@ +contract C { + function f(address payable a) public pure { + address payable b; + address c = a; + c = b; + } +}
\ No newline at end of file diff --git a/test/libsolidity/syntaxTests/types/address_to_contract_implicitly.sol b/test/libsolidity/syntaxTests/types/address_to_contract_implicitly.sol deleted file mode 100644 index efab7c27..00000000 --- a/test/libsolidity/syntaxTests/types/address_to_contract_implicitly.sol +++ /dev/null @@ -1,7 +0,0 @@ -contract C { - function f() public view { - C c = address(2); - } -} -// ---- -// TypeError: (46-62): Type address is not implicitly convertible to expected type contract C. |