Merge pull request #9344 from ethereum/issue-3412

Allow overrides to have a more strict mutability than super
This commit is contained in:
chriseth 2020-07-16 18:50:51 +02:00 committed by GitHub
commit ba21d26f88
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 113 additions and 8 deletions

View File

@ -21,6 +21,7 @@ Breaking changes:
Language Features:
* Yul: Disallow EVM instruction `pc()`.
* Yul: Disallow consecutive and trailing dots in identifiers. Leading dots were already disallowed.
* Inheritance: Allow overrides to have stricter state mutability: ``view`` can override ``nonpayable`` and ``pure`` can override ``view``.
Compiler Features:

View File

@ -203,23 +203,29 @@ Function Overriding
Base functions can be overridden by inheriting contracts to change their
behavior if they are marked as ``virtual``. The overriding function must then
use the ``override`` keyword in the function header as shown in this example:
use the ``override`` keyword in the function header.
The overriding function may only change the visibility of the overridden function from ``external`` to ``public``.
The mutability may be changed to a more strict one following the order:
``nonpayable`` can be overridden by ``view`` and ``pure``. ``view`` can be overridden by ``pure``.
``payable`` is an exception and cannot be changed to any other mutability.
The following example demonstrates changing mutability and visibility:
::
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.0 <0.8.0;
pragma solidity >0.6.99 <0.8.0;
contract Base
{
function foo() virtual public {}
function foo() virtual external view {}
}
contract Middle is Base {}
contract Inherited is Middle
{
function foo() public override {}
function foo() override public pure {}
}
For multiple inheritance, the most derived base contracts that define the same

View File

@ -587,7 +587,13 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr
// This is only relevant for a function overriding a function.
if (_overriding.isFunction())
{
if (_overriding.stateMutability() != _super.stateMutability())
// Stricter mutability is always okay except when super is Payable
if ((
_overriding.stateMutability() > _super.stateMutability() ||
_super.stateMutability() == StateMutability::Payable
) &&
_overriding.stateMutability() != _super.stateMutability()
)
overrideError(
_overriding,
_super,

View File

@ -1,5 +1,3 @@
contract B { function f() virtual public {} }
contract C is B { function f() public view {} }
contract C is B { function f() override public view {} }
// ----
// TypeError 9456: (64-91): Overriding function is missing "override" specifier.
// TypeError 6959: (64-91): Overriding function changes state mutability from "nonpayable" to "view".

View File

@ -0,0 +1,24 @@
contract A {
function foo() external pure virtual returns (uint256) {}
}
contract B is A {
function foo() external pure override virtual returns (uint256) {}
}
contract C is A {
function foo() external view override virtual returns (uint256) {}
}
contract D is B, C {
function foo() external override(B, C) virtual returns (uint256) {}
}
contract E is C, B {
function foo() external pure override(B, C) virtual returns (uint256) {}
}
contract F is C, B {
function foo() external payable override(B, C) virtual returns (uint256) {}
}
// ----
// TypeError 6959: (181-247): Overriding function changes state mutability from "pure" to "view".
// TypeError 6959: (272-339): Overriding function changes state mutability from "pure" to "nonpayable".
// TypeError 6959: (272-339): Overriding function changes state mutability from "view" to "nonpayable".
// TypeError 6959: (461-536): Overriding function changes state mutability from "view" to "payable".
// TypeError 6959: (461-536): Overriding function changes state mutability from "pure" to "payable".

View File

@ -0,0 +1,16 @@
contract A {
function foo() internal view virtual returns (uint256) {}
}
contract B is A {
function foo() internal pure override virtual returns (uint256) {}
}
contract C is A {
function foo() internal view override virtual returns (uint256) {}
}
contract D is B, C {
function foo() internal pure override(B, C) virtual returns (uint256) {}
}
contract E is C, B {
function foo() internal pure override(B, C) virtual returns (uint256) {}
}
// ----

View File

@ -0,0 +1,8 @@
contract A {
function foo() public payable virtual returns (uint256) {}
}
contract B is A {
function foo() public override virtual returns (uint256) {}
}
// ----
// TypeError 6959: (94-153): Overriding function changes state mutability from "payable" to "nonpayable".

View File

@ -0,0 +1,7 @@
contract A {
function foo() internal virtual returns (uint256) {}
}
contract B is A {
function foo() internal view override virtual returns (uint256) {}
}
// ----

View File

@ -0,0 +1,7 @@
contract A {
function foo() internal view virtual returns (uint256) {}
}
contract B is A {
function foo() internal pure override virtual returns (uint256) {}
}
// ----

View File

@ -0,0 +1,8 @@
contract A {
function foo() public payable virtual returns (uint256) {}
}
contract B is A {
function foo() public view override virtual returns (uint256) {}
}
// ----
// TypeError 6959: (94-158): Overriding function changes state mutability from "payable" to "view".

View File

@ -0,0 +1,8 @@
contract A {
function foo() public payable virtual returns (uint256) {}
}
contract B is A {
function foo() public pure override virtual returns (uint256) {}
}
// ----
// TypeError 6959: (94-158): Overriding function changes state mutability from "payable" to "pure".

View File

@ -0,0 +1,8 @@
contract A {
function foo() public virtual returns (uint256) {}
}
contract B is A {
function foo() public payable override virtual returns (uint256) {}
}
// ----
// TypeError 6959: (86-153): Overriding function changes state mutability from "nonpayable" to "payable".

View File

@ -0,0 +1,8 @@
contract A {
function foo() public view virtual returns (uint256) {}
}
contract B is A {
function foo() public payable override virtual returns (uint256) {}
}
// ----
// TypeError 6959: (91-158): Overriding function changes state mutability from "view" to "payable".