aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Changelog.md2
-rw-r--r--docs/common-patterns.rst2
-rw-r--r--docs/contracts.rst15
-rw-r--r--docs/control-structures.rst2
-rw-r--r--docs/miscellaneous.rst10
-rw-r--r--docs/security-considerations.rst6
-rw-r--r--docs/solidity-by-example.rst18
-rw-r--r--docs/types.rst27
-rw-r--r--docs/units-and-global-variables.rst14
-rw-r--r--libsolidity/analysis/GlobalContext.cpp4
-rw-r--r--libsolidity/analysis/ReferencesResolver.cpp18
-rw-r--r--libsolidity/analysis/TypeChecker.cpp48
-rw-r--r--libsolidity/ast/Types.cpp74
-rw-r--r--libsolidity/ast/Types.h15
-rw-r--r--libsolidity/codegen/ABIFunctions.cpp8
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp17
-rw-r--r--test/libsolidity/syntaxTests/parsing/address_in_struct.sol6
-rw-r--r--test/libsolidity/syntaxTests/parsing/address_nonpayable.sol7
-rw-r--r--test/libsolidity/syntaxTests/parsing/address_payable.sol7
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_abi_decode.sol6
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_constant.sol7
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_constant_assignment.sol11
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_in_struct_fail.sol11
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_in_struct_fine.sol20
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_nonpayable_selfdestruct.sol7
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_payable_external_overload.sol7
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_payable_internal_overload_nonpayable.sol10
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_payable_internal_overload_payable.sol10
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_payable_memory_array_conversion.sol11
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_payable_public_overload.sol7
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_payable_selfdestruct.sol5
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_payable_storage_array_conversion.sol11
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_payable_storage_array_conversion_fail.sol11
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_to_contract_implicitly.sol7
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_to_contract_payable_fallback.sol8
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_to_payable_address.sol10
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_tuple_fail.sol8
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_tuple_fine.sol6
-rw-r--r--test/libsolidity/syntaxTests/types/address/contract_no_fallback_to_payable_address.sol8
-rw-r--r--test/libsolidity/syntaxTests/types/address/contract_non_payable_fallback_to_payable_address.sol10
-rw-r--r--test/libsolidity/syntaxTests/types/address/contract_payable_fallback_to_payable_address.sol9
-rw-r--r--test/libsolidity/syntaxTests/types/address/contract_payable_fallback_to_payable_address_implicitly.sol10
-rw-r--r--test/libsolidity/syntaxTests/types/address/literal_to_address.sol8
-rw-r--r--test/libsolidity/syntaxTests/types/address/literal_to_payable_address.sol8
-rw-r--r--test/libsolidity/syntaxTests/types/address/nonpayable_address_to_contract_payable_fallback.sol10
-rw-r--r--test/libsolidity/syntaxTests/types/address/payable_address_to_address.sol7
-rw-r--r--test/libsolidity/syntaxTests/types/address_to_contract_implicitly.sol7
47 files changed, 468 insertions, 82 deletions
diff --git a/Changelog.md b/Changelog.md
index 846ae1f5..18062c9c 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.
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/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/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/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.