Merge pull request #7870 from ethereum/unimplementedRequireVirtual

Require virtual for unimplemented functions.
This commit is contained in:
chriseth 2019-12-03 11:21:38 +01:00 committed by GitHub
commit b5d3b95307
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 131 additions and 126 deletions

View File

@ -529,11 +529,11 @@ As an example, the code
pragma experimental ABIEncoderV2;
abstract contract Test {
contract Test {
struct S { uint a; uint[] b; T[] c; }
struct T { uint x; uint y; }
function f(S memory s, T memory t, uint a) public;
function g() public returns (S memory s, T memory t, uint a);
function f(S memory s, T memory t, uint a) public {}
function g() public returns (S memory s, T memory t, uint a) {}
}
would result in the JSON:

View File

@ -15,7 +15,7 @@ provided (no implementation body ``{ }`` was given).::
pragma solidity >=0.4.0 <0.7.0;
abstract contract Feline {
function utterance() public returns (bytes32);
function utterance() public virtual returns (bytes32);
}
Such abstract contracts can not be instantiated directly. This is also true, if an abstract contract itself does implement

View File

@ -53,13 +53,13 @@ Details are given in the following example.
// without body. If a contract does not implement all
// functions it can only be used as an interface.
abstract contract Config {
function lookup(uint id) public returns (address adr);
function lookup(uint id) public virtual returns (address adr);
}
abstract contract NameReg {
function register(bytes32 name) public;
function unregister() public;
function register(bytes32 name) public virtual;
function unregister() public virtual;
}

View File

@ -433,6 +433,8 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
m_errorReporter.typeError(_function.location(), "Constructor must be implemented if declared.");
else if (isLibraryFunction)
m_errorReporter.typeError(_function.location(), "Library functions must be implemented if declared.");
else if (!_function.virtualSemantics())
m_errorReporter.typeError(_function.location(), "Functions without implementation must be marked virtual.");
if (_function.isFallback())

View File

@ -87,7 +87,7 @@ virtual returns (bool success);
}
abstract contract tokenRecipient {
function receiveApproval(address _from, uint256 _value, address _token, bytes memory _extraData) public;
function receiveApproval(address _from, uint256 _value, address _token, bytes memory _extraData) public virtual;
}
contract Token is TokenInterface {

View File

@ -10464,7 +10464,7 @@ BOOST_AUTO_TEST_CASE(mutex)
BOOST_AUTO_TEST_CASE(calling_nonexisting_contract_throws)
{
char const* sourceCode = R"YY(
abstract contract D { function g() public; }
abstract contract D { function g() public virtual; }
contract C {
D d = D(0x1212);
function f() public returns (uint) {

View File

@ -49,7 +49,7 @@ BOOST_AUTO_TEST_CASE(function_no_implementation)
SourceUnit const* sourceUnit = nullptr;
char const* text = R"(
abstract contract test {
function functionName(bytes32 input) public returns (bytes32 out);
function functionName(bytes32 input) public virtual returns (bytes32 out);
}
)";
sourceUnit = parseAndAnalyse(text);
@ -83,7 +83,7 @@ BOOST_AUTO_TEST_CASE(abstract_contract_with_overload)
{
SourceUnit const* sourceUnit = nullptr;
char const* text = R"(
abstract contract base { function foo(bool) public; }
abstract contract base { function foo(bool) public virtual; }
abstract contract derived is base { function foo(uint) public {} }
)";
sourceUnit = parseAndAnalyse(text);
@ -100,7 +100,7 @@ BOOST_AUTO_TEST_CASE(implement_abstract_via_constructor)
{
SourceUnit const* sourceUnit = nullptr;
char const* text = R"(
abstract contract base { function foo() public; }
abstract contract base { function foo() public virtual; }
abstract contract foo is base { constructor() public {} }
)";
sourceUnit = parseAndAnalyse(text);
@ -357,7 +357,7 @@ BOOST_AUTO_TEST_CASE(dynamic_return_types_not_possible)
{
char const* sourceCode = R"(
abstract contract C {
function f(uint) public returns (string memory);
function f(uint) public virtual returns (string memory);
function g() public {
string memory x = this.f(2);
// we can assign to x but it is not usable.

View File

@ -2,7 +2,7 @@ pragma experimental SMTChecker;
abstract contract D
{
function g(uint x) public;
function g(uint x) public virtual;
}
contract C
@ -17,4 +17,4 @@ contract C
}
}
// ----
// Warning: (249-263): Assertion violation happens here
// Warning: (257-271): Assertion violation happens here

View File

@ -2,7 +2,7 @@ pragma experimental SMTChecker;
abstract contract D
{
function g(uint x) public;
function g(uint x) public virtual;
}
contract C
@ -17,4 +17,4 @@ contract C
}
}
// ----
// Warning: (289-313): Assertion violation happens here
// Warning: (297-321): Assertion violation happens here

View File

@ -2,7 +2,7 @@ pragma experimental SMTChecker;
abstract contract D
{
function g(uint x) public;
function g(uint x) public virtual;
}
contract C
@ -18,4 +18,4 @@ contract C
}
}
// ----
// Warning: (347-371): Assertion violation happens here
// Warning: (355-379): Assertion violation happens here

View File

@ -1,5 +1,5 @@
contract A {
function a() public;
function a() public virtual;
}
// ----
// TypeError: (0-39): Contract "A" should be marked as abstract.
// TypeError: (0-47): Contract "A" should be marked as abstract.

View File

@ -1,7 +1,7 @@
abstract contract A {
function a() public;
function a() public virtual;
}
contract B is A {
}
// ----
// TypeError: (49-68): Contract "B" should be marked as abstract.
// TypeError: (57-76): Contract "B" should be marked as abstract.

View File

@ -1,5 +1,5 @@
abstract contract C {
function f() internal returns(uint[] storage);
function g() internal returns(uint[] storage s);
function f() internal virtual returns(uint[] storage);
function g() internal virtual returns(uint[] storage s);
}
// ----

View File

@ -1,4 +1,4 @@
abstract contract test {
function f(bytes calldata) external;
contract test {
function f(bytes calldata) external {}
}
// ----

View File

@ -1,4 +1,4 @@
abstract contract test {
function f(bytes memory) internal;
contract test {
function f(bytes memory) internal {}
}
// ----

View File

@ -1,4 +1,4 @@
abstract contract test {
function f(bytes storage) internal;
contract test {
function f(bytes storage) internal {}
}
// ----

View File

@ -1,4 +1,4 @@
abstract contract test {
function f(bytes memory) public;
contract test {
function f(bytes memory) public {}
}
// ----

View File

@ -1,4 +1,4 @@
abstract contract X { function test() internal returns (uint256); }
abstract contract X { function test() internal virtual returns (uint256); }
contract Y is X {
uint256 public test = 42;
}
@ -6,4 +6,4 @@ contract T {
constructor() public { new Y(); }
}
// ----
// DeclarationError: (90-114): Identifier already declared.
// DeclarationError: (98-122): Identifier already declared.

View File

@ -1,4 +1,4 @@
abstract contract X { function test() private returns (uint256); }
abstract contract X { function test() private returns (uint256) {} }
contract Y is X {
uint256 public test = 42;
}

View File

@ -1,4 +1,4 @@
abstract contract X { function test() public returns (uint256); }
abstract contract X { function test() public virtual returns (uint256); }
contract Y is X {
uint256 public test = 42;
}
@ -6,4 +6,4 @@ contract T {
constructor() public { new Y(); }
}
// ----
// DeclarationError: (88-112): Identifier already declared.
// DeclarationError: (96-120): Identifier already declared.

View File

@ -3,9 +3,9 @@ abstract contract A {
function test() internal virtual returns (uint256);
function test2() internal virtual returns (uint256);
}
abstract contract X is A {
contract X is A {
int public override testvar;
function test() internal override returns (uint256);
function test2() internal override(A) returns (uint256);
function test() internal override returns (uint256) {}
function test2() internal override(A) returns (uint256) {}
}
// ----

View File

@ -3,12 +3,12 @@ abstract contract A {
function foo() internal virtual returns (uint256);
}
abstract contract B {
function foo() internal returns (uint256);
function foo() internal virtual returns (uint256);
function test() internal virtual returns (uint256);
}
abstract contract X is A, B {
int public override testvar;
function test() internal override returns (uint256);
function test() internal override returns (uint256) {}
}
// ----
// TypeError: (218-333): Derived contract must override function "foo". Function with the same name and parameter types defined in two or more base classes.
// TypeError: (226-343): Derived contract must override function "foo". Function with the same name and parameter types defined in two or more base classes.

View File

@ -14,7 +14,7 @@ abstract contract D is C {
function foo() internal override virtual returns (uint256);
}
abstract contract X is D {
function foo() internal override returns (uint256);
contract X is D {
function foo() internal override returns (uint256) {}
}
// ----

View File

@ -2,8 +2,8 @@ interface A {
function test() external returns (uint256);
function test2() external returns (uint256);
}
abstract contract X is A {
function test() external override returns (uint256);
function test2() external override(A) returns (uint256);
contract X is A {
function test() external override returns (uint256) {}
function test2() external override(A) returns (uint256) {}
}
// ----

View File

@ -7,8 +7,8 @@ interface B {
function test() external returns (uint256);
function test2() external returns (uint256);
}
abstract contract X is A, B {
function test() external override(A, B) returns (uint256);
function test2() external override(B, A) returns (uint256);
contract X is A, B {
function test() external override(A, B) returns (uint256) {}
function test2() external override(B, A) returns (uint256) {}
}
// ----

View File

@ -1,11 +1,11 @@
abstract contract A {
function test() external virtual returns (uint256);
function test2() external returns (uint256);
function test2() external returns (uint256) {}
}
abstract contract X is A {
function test() external returns (uint256);
function test2() external override(A) returns (uint256);
function test() external returns (uint256) {}
function test2() external override(A) returns (uint256) {}
}
// ----
// TypeError: (151-194): Overriding function is missing 'override' specifier.
// TypeError: (76-120): Trying to override non-virtual function. Did you forget to add "virtual"?
// TypeError: (153-198): Overriding function is missing 'override' specifier.
// TypeError: (76-122): Trying to override non-virtual function. Did you forget to add "virtual"?

View File

@ -1,7 +1,7 @@
abstract contract A {
int public testvar;
function foo() internal virtual returns (uint256);
function test(uint8 _a) internal virtual returns (uint256);
function test(uint8 _a) internal virtual returns (uint256) {}
}
abstract contract B {
function foo() internal virtual returns (uint256);
@ -13,9 +13,9 @@ abstract contract C {
abstract contract D {
function foo() internal virtual returns (uint256);
}
abstract contract X is A, B, C, D {
contract X is A, B, C, D {
int public override testvar;
function test() internal override returns (uint256);
function foo() internal override(A, B, C, D) returns (uint256);
function test() internal override returns (uint256) {}
function foo() internal override(A, B, C, D) returns (uint256) {}
}
// ----

View File

@ -1,7 +1,7 @@
abstract contract A {
int public testvar;
function foo() internal virtual returns (uint256);
function test(uint8 _a) internal returns (uint256);
function test(uint8 _a) internal virtual returns (uint256);
}
abstract contract B {
function foo() internal virtual returns (uint256);
@ -10,6 +10,6 @@ abstract contract B {
abstract contract C is A {
}
abstract contract D is A, B, C {
function foo() internal override(A, B) returns (uint256);
function foo() internal override(A, B) virtual returns (uint256);
}
// ----

View File

@ -16,11 +16,11 @@ abstract contract D {
}
abstract contract X is A, B, C, D {
int public override testvar;
function test() internal override(B, D, D) returns (uint256);
function foo() internal override(A, C, B, B, B, D ,D) returns (uint256);
function test() internal override(B, D, D) virtual returns (uint256);
function foo() internal override(A, C, B, B, B, D ,D) virtual returns (uint256);
}
// ----
// TypeError: (599-600): Duplicate contract "D" found in override list of "test".
// TypeError: (664-665): Duplicate contract "B" found in override list of "foo".
// TypeError: (667-668): Duplicate contract "B" found in override list of "foo".
// TypeError: (673-674): Duplicate contract "D" found in override list of "foo".
// TypeError: (672-673): Duplicate contract "B" found in override list of "foo".
// TypeError: (675-676): Duplicate contract "B" found in override list of "foo".
// TypeError: (681-682): Duplicate contract "D" found in override list of "foo".

View File

@ -16,9 +16,9 @@ abstract contract D {
}
abstract contract X is A, B, C, D {
int public override testvar;
function test() internal override(B, D, C) returns (uint256);
function foo() internal override(A, C) returns (uint256);
function test() internal override(B, D, C) virtual returns (uint256);
function foo() internal override(A, C) virtual returns (uint256);
}
// ----
// TypeError: (584-601): Invalid contract specified in override list: C.
// TypeError: (646-660): Function needs to specify overridden contracts B and D.
// TypeError: (654-668): Function needs to specify overridden contracts B and D.

View File

@ -8,7 +8,7 @@ abstract contract B {
}
abstract contract X is A, B {
int public override testvar;
function test() internal override returns (uint256);
function test() internal override virtual returns (uint256);
}
// ----
// TypeError: (224-339): Derived contract must override function "foo". Function with the same name and parameter types defined in two or more base classes.
// TypeError: (224-347): Derived contract must override function "foo". Function with the same name and parameter types defined in two or more base classes.

View File

@ -18,9 +18,9 @@ abstract contract X is A, B, C, D {
enum ENUM { F,G,H }
int public override testvar;
function test() internal override returns (uint256);
function foo() internal override(MyStruct, ENUM, A, B, C, D) returns (uint256);
function test() internal override virtual returns (uint256);
function foo() internal override(MyStruct, ENUM, A, B, C, D) virtual returns (uint256);
}
// ----
// TypeError: (645-653): Expected contract but got struct X.MyStruct.
// TypeError: (655-659): Expected contract but got enum X.ENUM.
// TypeError: (653-661): Expected contract but got struct X.MyStruct.
// TypeError: (663-667): Expected contract but got enum X.ENUM.

View File

@ -2,8 +2,7 @@ contract A {
uint public x;
}
contract C is A {
function x() public returns (uint);
function x() public returns (uint) {}
}
// ----
// DeclarationError: (50-85): Identifier already declared.
// TypeError: (50-85): Redeclaring an already implemented function as abstract
// DeclarationError: (50-87): Identifier already declared.

View File

@ -2,7 +2,7 @@ abstract contract A {
function test() private virtual returns (uint256);
}
abstract contract X is A {
function test() private override returns (uint256);
function test() private override returns (uint256) {}
}
// ----
// TypeError: (23-73): "virtual" and "private" cannot be used together.

View File

@ -0,0 +1,5 @@
abstract contract C {
function f() external;
}
// ----
// TypeError: (23-45): Functions without implementation must be marked virtual.

View File

@ -5,9 +5,9 @@
abstract contract C
{
modifier only_owner() { _; }
function foo() only_owner public;
function bar() public only_owner;
function foo() only_owner public virtual;
function bar() public only_owner virtual;
}
// ----
// SyntaxError: (212-245): Functions without implementation cannot have modifiers.
// SyntaxError: (250-283): Functions without implementation cannot have modifiers.
// SyntaxError: (212-253): Functions without implementation cannot have modifiers.
// SyntaxError: (258-299): Functions without implementation cannot have modifiers.

View File

@ -1,4 +1,4 @@
abstract contract C {
contract C {
function f() public {
uint a = two();
uint b = three();
@ -13,17 +13,17 @@ abstract contract C {
(uint a1, uint b1, uint c1, uint d1) = three();
(uint a2, uint b2, uint c2) = four();
}
function one() public pure returns (uint);
function two() public pure returns (uint, uint);
function three() public pure returns (uint, uint, uint);
function four() public pure returns (uint, uint, uint, uint);
function one() public pure returns (uint) {}
function two() public pure returns (uint, uint) {}
function three() public pure returns (uint, uint, uint) {}
function four() public pure returns (uint, uint, uint, uint) {}
}
// ----
// TypeError: (56-70): Different number of components on the left hand side (1) than on the right hand side (2).
// TypeError: (80-96): Different number of components on the left hand side (1) than on the right hand side (3).
// TypeError: (106-121): Different number of components on the left hand side (1) than on the right hand side (4).
// TypeError: (163-207): Different number of components on the left hand side (4) than on the right hand side (1).
// TypeError: (217-252): Different number of components on the left hand side (3) than on the right hand side (1).
// TypeError: (262-288): Different number of components on the left hand side (2) than on the right hand side (1).
// TypeError: (330-376): Different number of components on the left hand side (4) than on the right hand side (3).
// TypeError: (386-422): Different number of components on the left hand side (3) than on the right hand side (4).
// TypeError: (47-61): Different number of components on the left hand side (1) than on the right hand side (2).
// TypeError: (71-87): Different number of components on the left hand side (1) than on the right hand side (3).
// TypeError: (97-112): Different number of components on the left hand side (1) than on the right hand side (4).
// TypeError: (154-198): Different number of components on the left hand side (4) than on the right hand side (1).
// TypeError: (208-243): Different number of components on the left hand side (3) than on the right hand side (1).
// TypeError: (253-279): Different number of components on the left hand side (2) than on the right hand side (1).
// TypeError: (321-367): Different number of components on the left hand side (4) than on the right hand side (3).
// TypeError: (377-413): Different number of components on the left hand side (3) than on the right hand side (4).

View File

@ -12,11 +12,11 @@ abstract contract C {
(,uint m, uint n,) = five();
a;b;c;d;e;f;g;h;i;j;k;l;m;n;
}
function one() public pure returns (uint);
function two() public pure returns (uint, uint);
function three() public pure returns (uint, uint, uint);
function four() public pure returns (uint, uint, uint, uint);
function five() public pure returns (uint, uint, uint, uint, uint);
function one() public pure returns (uint) {}
function two() public pure returns (uint, uint) {}
function three() public pure returns (uint, uint, uint) {}
function four() public pure returns (uint, uint, uint, uint) {}
function five() public pure returns (uint, uint, uint, uint, uint) {}
}
// ----
// TypeError: (62-81): Different number of components on the left hand side (2) than on the right hand side (3).

View File

@ -1,7 +1,7 @@
contract base { function foo() public; }
contract base { function foo() public virtual; }
contract derived {
base b;
function foo() public { b = new base(); }
}
// ----
// TypeError: (0-40): Contract "base" should be marked as abstract.
// TypeError: (0-48): Contract "base" should be marked as abstract.

View File

@ -1,6 +1,5 @@
abstract contract base { function foo() public virtual; }
contract derived is base { function foo() public virtual override {} }
contract wrong is derived { function foo() public; }
contract wrong is derived { function foo() public virtual override; }
// ----
// TypeError: (157-179): Overriding function is missing 'override' specifier.
// TypeError: (157-179): Redeclaring an already implemented function as abstract
// TypeError: (157-196): Redeclaring an already implemented function as abstract

View File

@ -1,5 +1,5 @@
abstract contract M {
function f(uint[] memory) public;
function f(int[] memory) public;
function f(uint[] memory) public virtual;
function f(int[] memory) public virtual;
}
// ----

View File

@ -1,4 +1,4 @@
abstract contract C {
function f(uint a) pure public returns (uint b);
function f(uint a) pure public virtual returns (uint b);
}
// ----

View File

@ -1,5 +1,5 @@
abstract contract C {
function transfer(uint) public;
function transfer(uint) public virtual;
function f() public {
this.transfer(10);
}

View File

@ -1,6 +1,6 @@
abstract contract C {
contract C {
/// @param id
function vote(uint id) public;
function vote(uint id) public {}
}
// ----
// DocstringParsingError: No description given for param id

View File

@ -1,6 +1,6 @@
abstract contract C {
/// @param
function vote(uint id) public;
function vote(uint id) public {}
}
// ----
// DocstringParsingError: End of tag @param not found

View File

@ -1,4 +1,4 @@
abstract contract test {
function functionName(bytes32 input) public returns (bytes32 out);
function functionName(bytes32 input) public virtual returns (bytes32 out);
}
// ----

View File

@ -2,7 +2,7 @@ abstract contract Test
{
function uint256_to_uint256(uint256 x) internal pure returns (uint256) { return x; }
function uint256_to_string(uint256 x) internal pure returns (string memory) { return x == 0 ? "a" : "b"; }
function uint256_to_string_storage(uint256) internal pure returns (string storage);
function uint256_to_string_storage(uint256) internal pure returns (string storage) {}
function string_to_uint256(string memory x) internal pure returns (uint256) { return bytes(x).length; }
function string_to_string(string memory x) internal pure returns (string memory) { return x; }
@ -33,10 +33,10 @@ abstract contract Test
}
}
// ----
// TypeError: (1227-1320): Type function (uint256) pure returns (string memory) is not implicitly convertible to expected type function (uint256) pure returns (uint256).
// TypeError: (1328-1434): Type function (uint256) pure returns (string storage pointer) is not implicitly convertible to expected type function (uint256) pure returns (string memory).
// TypeError: (1442-1540): Type function (uint256) pure returns (string memory) is not implicitly convertible to expected type function (string memory) pure returns (uint256).
// TypeError: (1548-1655): Type function (uint256) pure returns (string memory) is not implicitly convertible to expected type function (string memory) pure returns (string memory).
// TypeError: (1664-1775): Type function (uint256) pure returns (uint256) is not implicitly convertible to expected type function (uint256,uint256) pure returns (uint256).
// TypeError: (1783-1902): Type function (string memory) pure returns (string memory) is not implicitly convertible to expected type function (string memory,uint256) pure returns (string memory).
// TypeError: (1910-2034): Type function (string memory) pure returns (string memory) is not implicitly convertible to expected type function (string memory,string memory) pure returns (string memory).
// TypeError: (1229-1322): Type function (uint256) pure returns (string memory) is not implicitly convertible to expected type function (uint256) pure returns (uint256).
// TypeError: (1330-1436): Type function (uint256) pure returns (string storage pointer) is not implicitly convertible to expected type function (uint256) pure returns (string memory).
// TypeError: (1444-1542): Type function (uint256) pure returns (string memory) is not implicitly convertible to expected type function (string memory) pure returns (uint256).
// TypeError: (1550-1657): Type function (uint256) pure returns (string memory) is not implicitly convertible to expected type function (string memory) pure returns (string memory).
// TypeError: (1666-1777): Type function (uint256) pure returns (uint256) is not implicitly convertible to expected type function (uint256,uint256) pure returns (uint256).
// TypeError: (1785-1904): Type function (string memory) pure returns (string memory) is not implicitly convertible to expected type function (string memory,uint256) pure returns (string memory).
// TypeError: (1912-2036): Type function (string memory) pure returns (string memory) is not implicitly convertible to expected type function (string memory,string memory) pure returns (string memory).

View File

@ -4,9 +4,9 @@ interface I {
function f();
}
abstract contract C {
function g();
function g() {}
}
// ----
// SyntaxError: (158-171): No visibility specified. Did you intend to add "external"?
// SyntaxError: (200-213): No visibility specified. Did you intend to add "public"?
// SyntaxError: (200-215): No visibility specified. Did you intend to add "public"?
// TypeError: (158-171): Functions in interfaces must be declared external.