diff options
author | chriseth <chris@ethereum.org> | 2018-06-20 03:32:03 +0800 |
---|---|---|
committer | Alex Beregszaszi <alex@rtfs.hu> | 2018-08-01 18:04:35 +0800 |
commit | c8232d9759458d5f6e1442533457d8529686eea7 (patch) | |
tree | cb1d8f4876b4984213134ad56ff5fb15db867d57 | |
parent | 21888e246b771325ea55da39d7f335638da1a98e (diff) | |
download | dexon-solidity-c8232d9759458d5f6e1442533457d8529686eea7.tar.gz dexon-solidity-c8232d9759458d5f6e1442533457d8529686eea7.tar.zst dexon-solidity-c8232d9759458d5f6e1442533457d8529686eea7.zip |
Disallow conversion between unrelated contract types.
16 files changed, 99 insertions, 16 deletions
diff --git a/Changelog.md b/Changelog.md index da287000..bcd55955 100644 --- a/Changelog.md +++ b/Changelog.md @@ -40,6 +40,7 @@ Breaking Changes: * Type Checker: Disallow arithmetic operations for boolean variables. * Type Checker: Disallow tight packing of literals. This was already the case in the experimental 0.5.0 mode. * Type Checker: Disallow conversions between ``bytesX`` and ``uintY`` of different size. + * Type Checker: Disallow conversions between unrelated contract types. Explicit conversion via ``address`` can still achieve it. * Type Checker: Disallow empty tuple components. This was partly already the case in the experimental 0.5.0 mode. * Type Checker: Disallow multi-variable declarations with mismatching number of values. This was already the case in the experimental 0.5.0 mode. * Type Checker: Disallow specifying base constructor arguments multiple times in the same inheritance hierarchy. This was already the case in the experimental 0.5.0 mode. diff --git a/docs/contracts.rst b/docs/contracts.rst index e78c3ff7..e87c8a67 100644 --- a/docs/contracts.rst +++ b/docs/contracts.rst @@ -1,5 +1,7 @@ .. index:: ! contract +.. _contracts: + ########## Contracts ########## diff --git a/docs/types.rst b/docs/types.rst index d6767b54..3aad413d 100644 --- a/docs/types.rst +++ b/docs/types.rst @@ -192,6 +192,23 @@ The ``.gas()`` option is available on all three methods, while the ``.value()`` .. note:: The use of ``callcode`` is discouraged and will be removed in the future. +Contract Types +-------------- + +Every :ref:`contract<contracts>` defines its own type. Contracts can be implicitly converted +to contracts they inherit from. They can be explicitly converted from and to ``address`` types. + +The data representation of a contract is identical to that of the ``address`` type and +this type is also used in the :ref:`ABI<ABI>`. + +Contracts do not support any operators. + +The members of contract types are the external functions of the contract including +public state variables. + +.. note:: + Starting with version 0.5.0 contracts do not derive from the address type, but can still be explicitly converted to address. + .. index:: byte array, bytes32 diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 2c2d3b68..7b079f45 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -1403,15 +1403,15 @@ bool ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const { if (*this == _convertTo) return true; - if (_convertTo.category() == Category::Integer) - return dynamic_cast<IntegerType const&>(_convertTo).isAddress(); if (_convertTo.category() == Category::Contract) { auto const& bases = contractDefinition().annotation().linearizedBaseContracts; if (m_super && bases.size() <= 1) return false; - return find(m_super ? ++bases.begin() : bases.begin(), bases.end(), - &dynamic_cast<ContractType const&>(_convertTo).contractDefinition()) != bases.end(); + return find( + m_super ? ++bases.begin() : bases.begin(), bases.end(), + &dynamic_cast<ContractType const&>(_convertTo).contractDefinition() + ) != bases.end(); } return false; } @@ -1420,8 +1420,7 @@ bool ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const { return isImplicitlyConvertibleTo(_convertTo) || - _convertTo.category() == Category::Integer || - _convertTo.category() == Category::Contract; + _convertTo == IntegerType(160, IntegerType::Modifier::Address); } bool ContractType::isPayable() const diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 1a676b42..474a6f33 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -692,9 +692,9 @@ public: virtual Category category() const override { return Category::Contract; } explicit ContractType(ContractDefinition const& _contract, bool _super = false): m_contract(_contract), m_super(_super) {} - /// Contracts can be implicitly converted to super classes and to addresses. + /// Contracts can be implicitly converted only to base contracts. virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; - /// Contracts can be converted to themselves and to integers. + /// Contracts can only be explicitly converted to address types and base contracts. virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; virtual std::string richIdentifier() const override; diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 223250fa..f52d270d 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -9420,7 +9420,7 @@ BOOST_AUTO_TEST_CASE(failed_create) contract C { uint public x; constructor() public payable {} - function f(uint amount) public returns (address) { + function f(uint amount) public returns (D) { x++; return (new D).value(amount)(); } @@ -12524,10 +12524,10 @@ BOOST_AUTO_TEST_CASE(staticcall_for_view_and_pure) return (new C()).f(); } function fview() public returns (uint) { - return (CView(new C())).f(); + return (CView(address(new C()))).f(); } function fpure() public returns (uint) { - return (CPure(new C())).f(); + return (CPure(address(new C()))).f(); } } )"; diff --git a/test/libsolidity/syntaxTests/constructor/inconstructible_internal_constructor_inverted.sol b/test/libsolidity/syntaxTests/constructor/inconstructible_internal_constructor_inverted.sol index 2a199b3a..ea2ec8f6 100644 --- a/test/libsolidity/syntaxTests/constructor/inconstructible_internal_constructor_inverted.sol +++ b/test/libsolidity/syntaxTests/constructor/inconstructible_internal_constructor_inverted.sol @@ -3,11 +3,10 @@ contract B { A a; constructor() public { - a = new A(this); + a = new A(address(this)); } } contract A { - constructor(address a) internal {} + constructor(address) public {} } // ---- -// TypeError: (141-146): Contract with internal constructor cannot be created directly. diff --git a/test/libsolidity/syntaxTests/parsing/constructor_allowed_this.sol b/test/libsolidity/syntaxTests/parsing/constructor_allowed_this.sol index 9f714aea..b66253e4 100644 --- a/test/libsolidity/syntaxTests/parsing/constructor_allowed_this.sol +++ b/test/libsolidity/syntaxTests/parsing/constructor_allowed_this.sol @@ -3,9 +3,9 @@ contract A { } } contract B { - constructor(address) public { + constructor(C) public { } - function b(address) public returns (A) { + function b(C) public returns (A) { return new A(); } } diff --git a/test/libsolidity/syntaxTests/types/address_to_contract.sol b/test/libsolidity/syntaxTests/types/address_to_contract.sol new file mode 100644 index 00000000..629a3df0 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address_to_contract.sol @@ -0,0 +1,6 @@ +contract C { + function f() public pure returns (C c) { + c = C(address(2)); + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/types/address_to_contract_implicitly.sol b/test/libsolidity/syntaxTests/types/address_to_contract_implicitly.sol new file mode 100644 index 00000000..efab7c27 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/address_to_contract_implicitly.sol @@ -0,0 +1,7 @@ +contract C { + function f() public view { + C c = address(2); + } +} +// ---- +// TypeError: (46-62): Type address is not implicitly convertible to expected type contract C. diff --git a/test/libsolidity/syntaxTests/types/contract_to_address.sol b/test/libsolidity/syntaxTests/types/contract_to_address.sol new file mode 100644 index 00000000..ec2f8184 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/contract_to_address.sol @@ -0,0 +1,7 @@ +contract C { + function f() public view { + address a = address(this); + a; + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/types/contract_to_address_implicitly.sol b/test/libsolidity/syntaxTests/types/contract_to_address_implicitly.sol new file mode 100644 index 00000000..8be9daac --- /dev/null +++ b/test/libsolidity/syntaxTests/types/contract_to_address_implicitly.sol @@ -0,0 +1,8 @@ +contract C { + function f() public view { + address a = this; + a; + } +} +// ---- +// TypeError: (46-62): Type contract C is not implicitly convertible to expected type address. diff --git a/test/libsolidity/syntaxTests/types/contract_to_base.sol b/test/libsolidity/syntaxTests/types/contract_to_base.sol new file mode 100644 index 00000000..b0a24e62 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/contract_to_base.sol @@ -0,0 +1,9 @@ +contract A {} +contract B is A {} +contract C { + function f() public { + A a = new B(); + a; + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/types/contract_to_base_base.sol b/test/libsolidity/syntaxTests/types/contract_to_base_base.sol new file mode 100644 index 00000000..e99e5cdc --- /dev/null +++ b/test/libsolidity/syntaxTests/types/contract_to_base_base.sol @@ -0,0 +1,10 @@ +contract A {} +contract B is A {} +contract C is B {} +contract D { + function f() public { + A a = new C(); + a; + } +} +// ---- diff --git a/test/libsolidity/syntaxTests/types/contract_to_derived.sol b/test/libsolidity/syntaxTests/types/contract_to_derived.sol new file mode 100644 index 00000000..ac8df5d1 --- /dev/null +++ b/test/libsolidity/syntaxTests/types/contract_to_derived.sol @@ -0,0 +1,9 @@ +contract B {} +contract A is B {} +contract C { + function f() public pure { + A a = A(new B()); + } +} +// ---- +// TypeError: (85-95): Explicit type conversion not allowed from "contract B" to "contract A". diff --git a/test/libsolidity/syntaxTests/types/contract_to_unrelated_contract.sol b/test/libsolidity/syntaxTests/types/contract_to_unrelated_contract.sol new file mode 100644 index 00000000..b0a4875f --- /dev/null +++ b/test/libsolidity/syntaxTests/types/contract_to_unrelated_contract.sol @@ -0,0 +1,9 @@ +contract A {} +contract B {} +contract C { + function f() public pure { + B b = B(new A()); + } +} +// ---- +// TypeError: (80-90): Explicit type conversion not allowed from "contract A" to "contract B". |