Implement override checking

This commit is contained in:
Mathias Baumann
2019-10-30 17:31:33 +01:00
parent 5ff02c12e2
commit 6c6a9054b2
85 changed files with 965 additions and 204 deletions
+1 -1
View File
@@ -23,7 +23,7 @@ Such contracts cannot be compiled (even if they contain implemented functions al
}
contract Cat is Feline {
function utterance() public returns (bytes32) { return "miaow"; }
function utterance() public override returns (bytes32) { return "miaow"; }
}
If a contract inherits from an abstract contract and does not implement all non-implemented functions by overriding, it will itself be abstract.
+131 -9
View File
@@ -10,6 +10,9 @@ All function calls are virtual, which means that the most derived function
is called, except when the contract name is explicitly given or the
``super`` keyword is used.
All functions overriding a base function must specify the ``override`` keyword.
See :ref:`Function Overriding <function-overriding>` for more details.
When a contract inherits from other contracts, only a single
contract is created on the blockchain, and the code from all the base contracts
is compiled into the created contract. This means that all internal calls
@@ -74,7 +77,7 @@ Details are given in the following example.
// types of output parameters, that causes an error.
// Both local and message-based function calls take these overrides
// into account.
function kill() public {
function kill() public override {
if (msg.sender == owner) {
Config config = Config(0xD5f9D8D94886E70b06E474c3fB14Fd43E2f23970);
NameReg(config.lookup(1)).unregister();
@@ -94,6 +97,7 @@ Details are given in the following example.
if (msg.sender == owner) info = newInfo;
}
function kill() public override (Mortal, Named) { Named.kill(); }
function get() public view returns(uint r) { return info; }
uint info;
@@ -117,20 +121,20 @@ seen in the following example::
}
contract Base1 is mortal {
function kill() public { /* do cleanup 1 */ mortal.kill(); }
function kill() public override { /* do cleanup 1 */ mortal.kill(); }
}
contract Base2 is mortal {
function kill() public { /* do cleanup 2 */ mortal.kill(); }
function kill() public override { /* do cleanup 2 */ mortal.kill(); }
}
contract Final is Base1, Base2 {
function kill() public override(Base1, Base2) { Base2.kill(); }
}
A call to ``Final.kill()`` will call ``Base2.kill`` as the most
derived override, but this function will bypass
``Base1.kill``, basically because it does not even know about
``Base1``. The way around this is to use ``super``::
A call to ``Final.kill()`` will call ``Base2.kill`` because we specify it
explicitly in the final override, but this function will bypass
``Base1.kill``. The way around this is to use ``super``::
pragma solidity >=0.4.22 <0.7.0;
@@ -146,15 +150,16 @@ derived override, but this function will bypass
}
contract Base1 is mortal {
function kill() public { /* do cleanup 1 */ super.kill(); }
function kill() public override { /* do cleanup 1 */ super.kill(); }
}
contract Base2 is mortal {
function kill() public { /* do cleanup 2 */ super.kill(); }
function kill() public override { /* do cleanup 2 */ super.kill(); }
}
contract Final is Base1, Base2 {
function kill() public override(Base1, Base2) { super.kill(); }
}
If ``Base2`` calls a function of ``super``, it does not simply
@@ -168,6 +173,123 @@ not known in the context of the class where it is used,
although its type is known. This is similar for ordinary
virtual method lookup.
.. _function-overriding:
.. index:: ! overriding;function
Function Overriding
===================
Base functions can be overridden by inheriting contracts to change their
behavior. The overriding function must then use the ``override`` keyword in the
function header as shown in this example:
::
pragma solidity >=0.5.0 <0.7.0;
contract Base
{
function foo() public {}
}
contract Middle is Base {}
contract Inherited is Middle
{
function foo() public override {}
}
For multiple inheritance, the most derived base contracts that define the same
function must be specified explicitly after the ``override`` keyword.
In other words, you have to specify all base contracts that define the same function and have not yet been overridden by another base contract (on some path through the inheritance graph).
Additionally, if a contract inherits the same function from multiple (unrelated)
bases, it has to explicitly override it:
::
pragma solidity >=0.5.0 <0.7.0;
contract Base1
{
function foo() public {}
}
contract Base2
{
function foo() public {}
}
contract Inherited is Base1, Base2
{
// Derives from multiple bases defining foo(), so we must explicitly
// override it
function foo() public override(Base1, Base2) {}
}
A function defined in a common base contract does not have to be explicitly
overridden when used with multiple inheritance:
::
pragma solidity >=0.5.0 <0.7.0;
contract A { function f() public pure{} }
contract B is A {}
contract C is A {}
// No explicit override required
contract D is B, C {}
.. _modifier-overriding:
.. index:: ! overriding;modifier
Modifier Overriding
===================
Function modifiers can override each other. This works in the same way as
function overriding (except that there is no overloading for modifiers). The
``override`` keyword must be used in the overriding contract:
::
pragma solidity >=0.5.0 <0.7.0;
contract Base
{
modifier foo() {_;}
}
contract Inherited is Base
{
modifier foo() override {_;}
}
In case of multiple inheritance, all direct base contracts must be specified
explicitly:
::
pragma solidity >=0.5.0 <0.7.0;
contract Base1
{
modifier foo() {_;}
}
contract Base2
{
modifier foo() {_;}
}
contract Inherited is Base1, Base2
{
modifier foo() override(Base1, Base2) {_;}
}
.. index:: ! constructor
.. _constructor:
+5
View File
@@ -67,6 +67,11 @@ Function Modifiers
Function modifiers can be used to amend the semantics of functions in a declarative way
(see :ref:`modifiers` in the contracts section).
Overloading, that is, having the same modifier name with different parameters,
is not possible.
Like functions, modifiers can be :ref:`overridden <modifier-overriding>`.
::
pragma solidity >=0.4.22 <0.7.0;
+2 -2
View File
@@ -98,11 +98,11 @@ Yes::
contract B is A {
function spam() public pure {
function spam() public override pure {
// ...
}
function ham() public pure {
function ham() public override pure {
// ...
}
}