mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Make shadowing of inherited state variables an error.
This commit is contained in:
parent
b5d3b95307
commit
7bbdfe070f
@ -22,6 +22,7 @@ Breaking changes:
|
||||
* Source mappings: Add "modifier depth" as a fifth field in the source mappings.
|
||||
* AST: Inline assembly is exported as structured JSON instead of plain string.
|
||||
* General: ``private`` cannot be used together with ``virtual``.
|
||||
* Inheritance: State variable shadowing is now disallowed.
|
||||
|
||||
Language Features:
|
||||
* Allow global enums and structs.
|
||||
|
@ -38,6 +38,10 @@ This section lists purely syntactic changes that do not affect the behavior of e
|
||||
If the name contains a dot, its prefix up to the dot may not conflict with any declaration outside the inline
|
||||
assembly block.
|
||||
|
||||
* State variable shadowing is now disallowed. A derived contract can only
|
||||
declare a state variable ``x``, if there is no visible state variable with
|
||||
the same name in any of its bases.
|
||||
|
||||
|
||||
Semantic Only Changes
|
||||
=====================
|
||||
|
@ -19,6 +19,10 @@ is compiled into the created contract. This means that all internal calls
|
||||
to functions of base contracts also just use internal function calls
|
||||
(``super.f(..)`` will use JUMP and not a message call).
|
||||
|
||||
State variable shadowing is considered as an error. A derived contract can
|
||||
only declare a state variable ``x``, if there is no visible state variable
|
||||
with the same name in any of its bases.
|
||||
|
||||
The general inheritance system is very similar to
|
||||
`Python's <https://docs.python.org/3/tutorial/classes.html#inheritance>`_,
|
||||
especially concerning multiple inheritance, but there are also
|
||||
|
@ -345,10 +345,6 @@ void NameAndTypeResolver::importInheritedScope(ContractDefinition const& _base)
|
||||
Declaration const* conflictingDeclaration = m_currentScope->conflictingDeclaration(*declaration);
|
||||
solAssert(conflictingDeclaration, "");
|
||||
|
||||
// Usual shadowing is not an error
|
||||
if (dynamic_cast<VariableDeclaration const*>(declaration) && dynamic_cast<VariableDeclaration const*>(conflictingDeclaration))
|
||||
continue;
|
||||
|
||||
// Usual shadowing is not an error
|
||||
if (dynamic_cast<ModifierDefinition const*>(declaration) && dynamic_cast<ModifierDefinition const*>(conflictingDeclaration))
|
||||
continue;
|
||||
|
@ -5971,38 +5971,6 @@ BOOST_AUTO_TEST_CASE(invalid_enum_as_external_arg)
|
||||
ABI_CHECK(callContractFunction("test()"), encodeArgs());
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(proper_order_of_overwriting_of_attributes)
|
||||
{
|
||||
// bug #1798
|
||||
char const* sourceCode = R"(
|
||||
contract init {
|
||||
function isOk() public virtual returns (bool) { return false; }
|
||||
bool public ok = false;
|
||||
}
|
||||
contract fix {
|
||||
function isOk() public virtual returns (bool) { return true; }
|
||||
bool public ok = true;
|
||||
}
|
||||
|
||||
contract init_fix is init, fix {
|
||||
function checkOk() public returns (bool) { return ok; }
|
||||
function isOk() public override (init, fix) returns (bool) { return super.isOk(); }
|
||||
}
|
||||
contract fix_init is fix, init {
|
||||
function checkOk() public returns (bool) { return ok; }
|
||||
function isOk() public override (init, fix) returns (bool) { return super.isOk(); }
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode, 0, "init_fix");
|
||||
ABI_CHECK(callContractFunction("isOk()"), encodeArgs(true));
|
||||
ABI_CHECK(callContractFunction("ok()"), encodeArgs(true));
|
||||
|
||||
compileAndRun(sourceCode, 0, "fix_init");
|
||||
ABI_CHECK(callContractFunction("isOk()"), encodeArgs(false));
|
||||
ABI_CHECK(callContractFunction("ok()"), encodeArgs(false));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(struct_assign_reference_to_struct)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
@ -8051,42 +8019,6 @@ BOOST_AUTO_TEST_CASE(inherited_constant_state_var)
|
||||
ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(7)));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(multiple_inherited_state_vars)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
contract A {
|
||||
uint x = 7;
|
||||
}
|
||||
contract B {
|
||||
uint x = 9;
|
||||
}
|
||||
contract C is A, B {
|
||||
function a() public returns (uint) {
|
||||
return A.x;
|
||||
}
|
||||
function b() public returns (uint) {
|
||||
return B.x;
|
||||
}
|
||||
function a_set(uint _x) public returns (uint) {
|
||||
A.x = _x;
|
||||
return 1;
|
||||
}
|
||||
function b_set(uint _x) public returns (uint) {
|
||||
B.x = _x;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
compileAndRun(sourceCode, 0, "C");
|
||||
ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(7)));
|
||||
ABI_CHECK(callContractFunction("b()"), encodeArgs(u256(9)));
|
||||
ABI_CHECK(callContractFunction("a_set(uint256)", u256(1)), encodeArgs(u256(1)));
|
||||
ABI_CHECK(callContractFunction("b_set(uint256)", u256(3)), encodeArgs(u256(1)));
|
||||
ABI_CHECK(callContractFunction("a()"), encodeArgs(u256(1)));
|
||||
ABI_CHECK(callContractFunction("b()"), encodeArgs(u256(3)));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(constant_string_literal)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
|
@ -2,12 +2,10 @@ pragma experimental SMTChecker;
|
||||
|
||||
contract Base1 {
|
||||
uint x;
|
||||
uint private t;
|
||||
}
|
||||
|
||||
contract Base2 is Base1 {
|
||||
uint z;
|
||||
uint private t;
|
||||
}
|
||||
|
||||
contract C is Base2 {
|
||||
|
@ -9,3 +9,4 @@ contract X is A {
|
||||
function test2() internal override(A) returns (uint256) {}
|
||||
}
|
||||
// ----
|
||||
// DeclarationError: (171-198): Identifier already declared.
|
||||
|
@ -11,4 +11,5 @@ abstract contract X is A, B {
|
||||
function test() internal override returns (uint256) {}
|
||||
}
|
||||
// ----
|
||||
// DeclarationError: (257-284): Identifier already declared.
|
||||
// TypeError: (226-343): Derived contract must override function "foo". Function with the same name and parameter types defined in two or more base classes.
|
||||
|
@ -1,5 +1,4 @@
|
||||
abstract contract A {
|
||||
int public testvar;
|
||||
function foo() internal virtual returns (uint256);
|
||||
function test(uint8 _a) internal virtual returns (uint256) {}
|
||||
}
|
||||
@ -18,4 +17,3 @@ contract X is A, B, C, D {
|
||||
function test() internal override returns (uint256) {}
|
||||
function foo() internal override(A, B, C, D) returns (uint256) {}
|
||||
}
|
||||
// ----
|
||||
|
@ -20,6 +20,7 @@ abstract contract X is A, B, C, D {
|
||||
function foo() internal override(A, C, B, B, B, D ,D) virtual returns (uint256);
|
||||
}
|
||||
// ----
|
||||
// DeclarationError: (529-556): Identifier already declared.
|
||||
// TypeError: (599-600): Duplicate contract "D" found in override list of "test".
|
||||
// TypeError: (672-673): Duplicate contract "B" found in override list of "foo".
|
||||
// TypeError: (675-676): Duplicate contract "B" found in override list of "foo".
|
||||
|
@ -1,5 +1,4 @@
|
||||
abstract contract A {
|
||||
int public testvar;
|
||||
function foo() internal virtual returns (uint256);
|
||||
function test(uint8 _a) virtual internal returns (uint256);
|
||||
}
|
||||
@ -20,5 +19,5 @@ abstract contract X is A, B, C, D {
|
||||
function foo() internal override(A, C) virtual returns (uint256);
|
||||
}
|
||||
// ----
|
||||
// TypeError: (584-601): Invalid contract specified in override list: C.
|
||||
// TypeError: (654-668): Function needs to specify overridden contracts B and D.
|
||||
// TypeError: (563-580): Invalid contract specified in override list: C.
|
||||
// TypeError: (633-647): Function needs to specify overridden contracts B and D.
|
||||
|
@ -1,7 +0,0 @@
|
||||
abstract contract A {
|
||||
int public testvar;
|
||||
}
|
||||
abstract contract X is A {
|
||||
int public override testvar;
|
||||
}
|
||||
// ----
|
@ -1,5 +1,4 @@
|
||||
abstract contract A {
|
||||
int public testvar;
|
||||
function foo() internal virtual returns (uint256);
|
||||
}
|
||||
abstract contract B {
|
||||
@ -11,4 +10,4 @@ abstract contract X is A, B {
|
||||
function test() internal override virtual returns (uint256);
|
||||
}
|
||||
// ----
|
||||
// TypeError: (224-347): Derived contract must override function "foo". Function with the same name and parameter types defined in two or more base classes.
|
||||
// TypeError: (203-326): Derived contract must override function "foo". Function with the same name and parameter types defined in two or more base classes.
|
||||
|
@ -1,5 +1,4 @@
|
||||
abstract contract A {
|
||||
int public testvar;
|
||||
function foo() internal virtual returns (uint256);
|
||||
function test(uint8 _a) internal virtual returns (uint256);
|
||||
}
|
||||
@ -22,5 +21,5 @@ abstract contract X is A, B, C, D {
|
||||
function foo() internal override(MyStruct, ENUM, A, B, C, D) virtual returns (uint256);
|
||||
}
|
||||
// ----
|
||||
// TypeError: (653-661): Expected contract but got struct X.MyStruct.
|
||||
// TypeError: (663-667): Expected contract but got enum X.ENUM.
|
||||
// TypeError: (632-640): Expected contract but got struct X.MyStruct.
|
||||
// TypeError: (642-646): Expected contract but got enum X.ENUM.
|
||||
|
@ -0,0 +1,8 @@
|
||||
contract A {
|
||||
uint i;
|
||||
}
|
||||
contract B is A {
|
||||
uint i;
|
||||
}
|
||||
// ----
|
||||
// DeclarationError: (43-49): Identifier already declared.
|
@ -0,0 +1,6 @@
|
||||
contract A {
|
||||
uint private i;
|
||||
}
|
||||
contract B is A {
|
||||
uint i;
|
||||
}
|
Loading…
Reference in New Issue
Block a user