Disallow conversion between unrelated contract types.

This commit is contained in:
chriseth 2018-06-19 21:32:03 +02:00 committed by Alex Beregszaszi
parent 21888e246b
commit c8232d9759
16 changed files with 99 additions and 16 deletions

View File

@ -40,6 +40,7 @@ Breaking Changes:
* Type Checker: Disallow arithmetic operations for boolean variables. * 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 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 ``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 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 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. * 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.

View File

@ -1,5 +1,7 @@
.. index:: ! contract .. index:: ! contract
.. _contracts:
########## ##########
Contracts Contracts
########## ##########

View File

@ -192,6 +192,23 @@ The ``.gas()`` option is available on all three methods, while the ``.value()``
.. note:: .. note::
The use of ``callcode`` is discouraged and will be removed in the future. 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 .. index:: byte array, bytes32

View File

@ -1403,15 +1403,15 @@ bool ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{ {
if (*this == _convertTo) if (*this == _convertTo)
return true; return true;
if (_convertTo.category() == Category::Integer)
return dynamic_cast<IntegerType const&>(_convertTo).isAddress();
if (_convertTo.category() == Category::Contract) if (_convertTo.category() == Category::Contract)
{ {
auto const& bases = contractDefinition().annotation().linearizedBaseContracts; auto const& bases = contractDefinition().annotation().linearizedBaseContracts;
if (m_super && bases.size() <= 1) if (m_super && bases.size() <= 1)
return false; return false;
return find(m_super ? ++bases.begin() : bases.begin(), bases.end(), return find(
&dynamic_cast<ContractType const&>(_convertTo).contractDefinition()) != bases.end(); m_super ? ++bases.begin() : bases.begin(), bases.end(),
&dynamic_cast<ContractType const&>(_convertTo).contractDefinition()
) != bases.end();
} }
return false; return false;
} }
@ -1420,8 +1420,7 @@ bool ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{ {
return return
isImplicitlyConvertibleTo(_convertTo) || isImplicitlyConvertibleTo(_convertTo) ||
_convertTo.category() == Category::Integer || _convertTo == IntegerType(160, IntegerType::Modifier::Address);
_convertTo.category() == Category::Contract;
} }
bool ContractType::isPayable() const bool ContractType::isPayable() const

View File

@ -692,9 +692,9 @@ public:
virtual Category category() const override { return Category::Contract; } virtual Category category() const override { return Category::Contract; }
explicit ContractType(ContractDefinition const& _contract, bool _super = false): explicit ContractType(ContractDefinition const& _contract, bool _super = false):
m_contract(_contract), m_super(_super) {} 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; 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 bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual std::string richIdentifier() const override; virtual std::string richIdentifier() const override;

View File

@ -9420,7 +9420,7 @@ BOOST_AUTO_TEST_CASE(failed_create)
contract C { contract C {
uint public x; uint public x;
constructor() public payable {} constructor() public payable {}
function f(uint amount) public returns (address) { function f(uint amount) public returns (D) {
x++; x++;
return (new D).value(amount)(); return (new D).value(amount)();
} }
@ -12524,10 +12524,10 @@ BOOST_AUTO_TEST_CASE(staticcall_for_view_and_pure)
return (new C()).f(); return (new C()).f();
} }
function fview() public returns (uint) { function fview() public returns (uint) {
return (CView(new C())).f(); return (CView(address(new C()))).f();
} }
function fpure() public returns (uint) { function fpure() public returns (uint) {
return (CPure(new C())).f(); return (CPure(address(new C()))).f();
} }
} }
)"; )";

View File

@ -3,11 +3,10 @@
contract B { contract B {
A a; A a;
constructor() public { constructor() public {
a = new A(this); a = new A(address(this));
} }
} }
contract A { contract A {
constructor(address a) internal {} constructor(address) public {}
} }
// ---- // ----
// TypeError: (141-146): Contract with internal constructor cannot be created directly.

View File

@ -3,9 +3,9 @@ contract A {
} }
} }
contract B { contract B {
constructor(address) public { constructor(C) public {
} }
function b(address) public returns (A) { function b(C) public returns (A) {
return new A(); return new A();
} }
} }

View File

@ -0,0 +1,6 @@
contract C {
function f() public pure returns (C c) {
c = C(address(2));
}
}
// ----

View File

@ -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.

View File

@ -0,0 +1,7 @@
contract C {
function f() public view {
address a = address(this);
a;
}
}
// ----

View File

@ -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.

View File

@ -0,0 +1,9 @@
contract A {}
contract B is A {}
contract C {
function f() public {
A a = new B();
a;
}
}
// ----

View File

@ -0,0 +1,10 @@
contract A {}
contract B is A {}
contract C is B {}
contract D {
function f() public {
A a = new C();
a;
}
}
// ----

View File

@ -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".

View File

@ -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".