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. |  * 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. |  * AST: Inline assembly is exported as structured JSON instead of plain string. | ||||||
|  * General: ``private`` cannot be used together with ``virtual``. |  * General: ``private`` cannot be used together with ``virtual``. | ||||||
|  |  * Inheritance: State variable shadowing is now disallowed. | ||||||
| 
 | 
 | ||||||
| Language Features: | Language Features: | ||||||
|  * Allow global enums and structs. |  * 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 |   If the name contains a dot, its prefix up to the dot may not conflict with any declaration outside the inline | ||||||
|   assembly block. |   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 | 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 | to functions of base contracts also just use internal function calls | ||||||
| (``super.f(..)`` will use JUMP and not a message call). | (``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 | The general inheritance system is very similar to | ||||||
| `Python's <https://docs.python.org/3/tutorial/classes.html#inheritance>`_, | `Python's <https://docs.python.org/3/tutorial/classes.html#inheritance>`_, | ||||||
| especially concerning multiple inheritance, but there are also | 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); | 					Declaration const* conflictingDeclaration = m_currentScope->conflictingDeclaration(*declaration); | ||||||
| 					solAssert(conflictingDeclaration, ""); | 					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
 | 					// Usual shadowing is not an error
 | ||||||
| 					if (dynamic_cast<ModifierDefinition const*>(declaration) && dynamic_cast<ModifierDefinition const*>(conflictingDeclaration)) | 					if (dynamic_cast<ModifierDefinition const*>(declaration) && dynamic_cast<ModifierDefinition const*>(conflictingDeclaration)) | ||||||
| 						continue; | 						continue; | ||||||
|  | |||||||
| @ -5971,38 +5971,6 @@ BOOST_AUTO_TEST_CASE(invalid_enum_as_external_arg) | |||||||
| 	ABI_CHECK(callContractFunction("test()"), encodeArgs()); | 	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) | BOOST_AUTO_TEST_CASE(struct_assign_reference_to_struct) | ||||||
| { | { | ||||||
| 	char const* sourceCode = R"( | 	char const* sourceCode = R"( | ||||||
| @ -8051,42 +8019,6 @@ BOOST_AUTO_TEST_CASE(inherited_constant_state_var) | |||||||
| 	ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(7))); | 	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) | BOOST_AUTO_TEST_CASE(constant_string_literal) | ||||||
| { | { | ||||||
| 	char const* sourceCode = R"( | 	char const* sourceCode = R"( | ||||||
|  | |||||||
| @ -2,12 +2,10 @@ pragma experimental SMTChecker; | |||||||
| 
 | 
 | ||||||
| contract Base1 { | contract Base1 { | ||||||
| 	uint x; | 	uint x; | ||||||
| 	uint private t; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| contract Base2 is Base1 { | contract Base2 is Base1 { | ||||||
| 	uint z; | 	uint z; | ||||||
| 	uint private t; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| contract C is Base2 { | contract C is Base2 { | ||||||
|  | |||||||
| @ -9,3 +9,4 @@ contract X is A { | |||||||
| 	function test2() internal override(A) returns (uint256) {} | 	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) {} | 	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. | // 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 { | abstract contract A { | ||||||
| 	int public testvar; |  | ||||||
| 	function foo() internal virtual returns (uint256); | 	function foo() internal virtual returns (uint256); | ||||||
| 	function test(uint8 _a) 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 test() internal override returns (uint256) {} | ||||||
| 	function foo() internal override(A, B, C, D) 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); | 	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: (599-600): Duplicate contract "D" found in override list of "test". | ||||||
| // TypeError: (672-673): Duplicate contract "B" 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: (675-676): Duplicate contract "B" found in override list of "foo". | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| abstract contract A { | abstract contract A { | ||||||
| 	int public testvar; |  | ||||||
| 	function foo() internal virtual returns (uint256); | 	function foo() internal virtual returns (uint256); | ||||||
| 	function test(uint8 _a) virtual internal 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); | 	function foo() internal override(A, C) virtual returns (uint256); | ||||||
| } | } | ||||||
| // ---- | // ---- | ||||||
| // TypeError: (584-601): Invalid contract specified in override list: C. | // TypeError: (563-580): Invalid contract specified in override list: C. | ||||||
| // TypeError: (654-668): Function needs to specify overridden contracts B and D. | // 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 { | abstract contract A { | ||||||
| 	int public testvar; |  | ||||||
| 	function foo() internal virtual returns (uint256); | 	function foo() internal virtual returns (uint256); | ||||||
| } | } | ||||||
| abstract contract B { | abstract contract B { | ||||||
| @ -11,4 +10,4 @@ abstract contract X is A, B { | |||||||
| 	function test() internal override virtual returns (uint256); | 	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 { | abstract contract A { | ||||||
| 	int public testvar; |  | ||||||
| 	function foo() internal virtual returns (uint256); | 	function foo() internal virtual returns (uint256); | ||||||
| 	function test(uint8 _a) 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); | 	function foo() internal override(MyStruct, ENUM, A, B, C, D) virtual returns (uint256); | ||||||
| } | } | ||||||
| // ---- | // ---- | ||||||
| // TypeError: (653-661): Expected contract but got struct X.MyStruct. | // TypeError: (632-640): Expected contract but got struct X.MyStruct. | ||||||
| // TypeError: (663-667): Expected contract but got enum X.ENUM. | // 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