diff --git a/Changelog.md b/Changelog.md index 9c2d9a384..2472d9467 100644 --- a/Changelog.md +++ b/Changelog.md @@ -9,6 +9,8 @@ Compiler Features: Bugfixes: * Inline Assembly: Fix internal error when accessing incorrect constant variables. + * Inheritance: Allow public state variables to override functions with dynamic memory types in their return values. + * JSON AST: Always add pointer suffix for memory reference types. ### 0.6.4 (2020-03-10) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index d760e0810..9ed35e694 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -1487,11 +1487,19 @@ TypeResult ReferenceType::unaryOperatorResult(Token _operator) const case DataLocation::Memory: return TypeProvider::emptyTuple(); case DataLocation::Storage: - return m_isPointer ? nullptr : TypeProvider::emptyTuple(); + return isPointer() ? nullptr : TypeProvider::emptyTuple(); } return nullptr; } +bool ReferenceType::isPointer() const +{ + if (m_location == DataLocation::Storage) + return m_isPointer; + else + return true; +} + TypePointer ReferenceType::copyForLocationIfReference(Type const* _type) const { return TypeProvider::withLocationIfReference(m_location, _type); @@ -1502,7 +1510,7 @@ string ReferenceType::stringForReferencePart() const switch (m_location) { case DataLocation::Storage: - return string("storage ") + (m_isPointer ? "pointer" : "ref"); + return string("storage ") + (isPointer() ? "pointer" : "ref"); case DataLocation::CallData: return "calldata"; case DataLocation::Memory: @@ -1868,7 +1876,8 @@ u256 ArrayType::memoryDataSize() const std::unique_ptr ArrayType::copyForLocation(DataLocation _location, bool _isPointer) const { auto copy = make_unique(_location); - copy->m_isPointer = _isPointer; + if (_location == DataLocation::Storage) + copy->m_isPointer = _isPointer; copy->m_arrayKind = m_arrayKind; copy->m_baseType = copy->copyForLocationIfReference(m_baseType); copy->m_hasDynamicLength = m_hasDynamicLength; @@ -2247,7 +2256,8 @@ TypeResult StructType::interfaceType(bool _inLibrary) const std::unique_ptr StructType::copyForLocation(DataLocation _location, bool _isPointer) const { auto copy = make_unique(m_struct, _location); - copy->m_isPointer = _isPointer; + if (_location == DataLocation::Storage) + copy->m_isPointer = _isPointer; return copy; } diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 5aada86c3..73943b18a 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -701,7 +701,9 @@ public: /// pointer type, state variables are bound references. Assignments to pointers or deleting /// them will not modify storage (that will only change the pointer). Assignment from /// non-storage objects to a variable of storage pointer type is not possible. - bool isPointer() const { return m_isPointer; } + /// For anything other than storage, this always returns true because assignments + /// never change the contents of the original value. + bool isPointer() const; bool operator==(ReferenceType const& _other) const { diff --git a/test/libsolidity/ASTJSON/short_type_name_ref.json b/test/libsolidity/ASTJSON/short_type_name_ref.json index 0aa3d2984..501184c9c 100644 --- a/test/libsolidity/ASTJSON/short_type_name_ref.json +++ b/test/libsolidity/ASTJSON/short_type_name_ref.json @@ -54,7 +54,7 @@ "storageLocation": "memory", "typeDescriptions": { - "typeIdentifier": "t_array$_t_array$_t_uint256_$dyn_memory_$dyn_memory_ptr", + "typeIdentifier": "t_array$_t_array$_t_uint256_$dyn_memory_ptr_$dyn_memory_ptr", "typeString": "uint256[][]" }, "typeName": diff --git a/test/libsolidity/gasTests/abiv2.sol b/test/libsolidity/gasTests/abiv2.sol index f0892b83b..1fd96ff76 100644 --- a/test/libsolidity/gasTests/abiv2.sol +++ b/test/libsolidity/gasTests/abiv2.sol @@ -14,9 +14,9 @@ contract C { } // ---- // creation: -// codeDepositCost: 1120000 -// executionCost: 1160 -// totalCost: 1121160 +// codeDepositCost: 1094400 +// executionCost: 1134 +// totalCost: 1095534 // external: // a(): 1130 // b(uint256): infinite diff --git a/test/libsolidity/semanticTests/variables/public_state_overridding_dynamic_struct.sol b/test/libsolidity/semanticTests/variables/public_state_overridding_dynamic_struct.sol new file mode 100644 index 000000000..f6fa4d45e --- /dev/null +++ b/test/libsolidity/semanticTests/variables/public_state_overridding_dynamic_struct.sol @@ -0,0 +1,24 @@ +pragma experimental ABIEncoderV2; + +struct S { uint256 v; string s; } + +contract A +{ + function test() external virtual returns (uint256 v, string memory s) + { + v = 42; + s = "test"; + } +} +contract X is A +{ + S public override test; + + function set() public { test.v = 2; test.s = "statevar"; } +} + + +// ---- +// test() -> 0, 64, 0 +// set() -> +// test() -> 2, 0x40, 8, "statevar" diff --git a/test/libsolidity/semanticTests/variables/public_state_overridding_mapping_to_dynamic_struct.sol b/test/libsolidity/semanticTests/variables/public_state_overridding_mapping_to_dynamic_struct.sol new file mode 100644 index 000000000..404013ee6 --- /dev/null +++ b/test/libsolidity/semanticTests/variables/public_state_overridding_mapping_to_dynamic_struct.sol @@ -0,0 +1,26 @@ +pragma experimental ABIEncoderV2; + +struct S { uint256 v; string s; } + +contract A +{ + function test(uint256 x) external virtual returns (uint256 v, string memory s) + { + v = x; + s = "test"; + } +} +contract X is A +{ + mapping(uint256 => S) public override test; + + function set() public { test[42].v = 2; test[42].s = "statevar"; } +} + + +// ---- +// test(uint256): 0 -> 0, 64, 0 +// test(uint256): 42 -> 0, 64, 0 +// set() -> +// test(uint256): 0 -> 0, 64, 0 +// test(uint256): 42 -> 2, 0x40, 8, "statevar" diff --git a/test/libsolidity/syntaxTests/inheritance/override/public_var_override_mapping_to_dynamic_struct.sol b/test/libsolidity/syntaxTests/inheritance/override/public_var_override_mapping_to_dynamic_struct.sol new file mode 100644 index 000000000..d02284aef --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/public_var_override_mapping_to_dynamic_struct.sol @@ -0,0 +1,12 @@ +pragma experimental ABIEncoderV2; + +abstract contract C { + struct S { + uint256 x; + string y; + } + function f(address x) external virtual returns (uint256, string memory); +} +contract D is C { + mapping(address => S) public override f; +} diff --git a/test/libsolidity/syntaxTests/inheritance/override/public_var_override_struct_with_memory_element.sol b/test/libsolidity/syntaxTests/inheritance/override/public_var_override_struct_with_memory_element.sol new file mode 100644 index 000000000..4e6e02598 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/public_var_override_struct_with_memory_element.sol @@ -0,0 +1,13 @@ +pragma experimental ABIEncoderV2; + +abstract contract C { + struct S { + uint256 x; + string y; + } + + function f() external virtual returns (uint256, string memory); +} +contract D is C { + S public override f; +}