diff --git a/libsolidity/CompilerUtils.cpp b/libsolidity/CompilerUtils.cpp index 349877a29..d4e705a3c 100644 --- a/libsolidity/CompilerUtils.cpp +++ b/libsolidity/CompilerUtils.cpp @@ -274,10 +274,13 @@ void CompilerUtils::encodeToMemory( else { copyToStackTop(argSize - stackPos + dynPointers + 2, _givenTypes[i]->getSizeOnStack()); - if (targetType->isValueType()) - convertType(*_givenTypes[i], *targetType, true); solAssert(!!targetType, "Externalable type expected."); - storeInMemoryDynamic(*targetType, _padToWordBoundaries); + TypePointer type = targetType; + if (_givenTypes[i]->isInStorage()) + type = _givenTypes[i]; // delay conversion + else + convertType(*_givenTypes[i], *targetType, true); + storeInMemoryDynamic(*type, _padToWordBoundaries); } stackPos += _givenTypes[i]->getSizeOnStack(); } diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 12274c7ab..c98d76f3f 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -146,10 +146,13 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) { CompilerContext::LocationSetter locationSetter(m_context, _assignment); _assignment.getRightHandSide().accept(*this); - if (_assignment.getType()->isValueType()) - utils().convertType(*_assignment.getRightHandSide().getType(), *_assignment.getType()); - // We need this conversion mostly in the case of compound assignments. For non-value types - // the conversion is done in LValue::storeValue. + TypePointer type = _assignment.getRightHandSide().getType(); + if (!_assignment.getType()->isInStorage()) + { + utils().convertType(*type, *_assignment.getType()); + type = _assignment.getType(); + } + _assignment.getLeftHandSide().accept(*this); solAssert(!!m_currentLValue, "LValue not retrieved."); @@ -175,7 +178,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) m_context << eth::swapInstruction(itemSize + lvalueSize) << eth::Instruction::POP; } } - m_currentLValue->storeValue(*_assignment.getRightHandSide().getType(), _assignment.getLocation()); + m_currentLValue->storeValue(*type, _assignment.getLocation()); m_currentLValue.reset(); return false; } @@ -1119,14 +1122,10 @@ void ExpressionCompiler::appendExternalFunctionCall( void ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression) { + solAssert(_expectedType.isValueType(), "Not implemented for non-value types."); _expression.accept(*this); - if (_expectedType.isValueType()) - { - utils().convertType(*_expression.getType(), _expectedType, true); - utils().storeInMemoryDynamic(_expectedType); - } - else - utils().storeInMemoryDynamic(*_expression.getType()->mobileType()); + utils().convertType(*_expression.getType(), _expectedType, true); + utils().storeInMemoryDynamic(_expectedType); } void ExpressionCompiler::setLValueFromDeclaration(Declaration const& _declaration, Expression const& _expression) diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 0f86ac95f..70f7807c8 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -202,6 +202,8 @@ public: /// This returns the corresponding integer type for IntegerConstantTypes and the pointer type /// for storage reference types. virtual TypePointer mobileType() const { return shared_from_this(); } + /// @returns true if this type is a storage pointer or reference. + virtual bool isInStorage() const { return false; } /// Returns the list of all members of this type. Default implementation: no members. virtual MemberList const& getMembers() const { return EmptyMemberList; } @@ -374,6 +376,7 @@ public: virtual TypePointer copyForLocation(Location _location, bool _isPointer) const = 0; virtual TypePointer mobileType() const override { return copyForLocation(m_location, true); } + virtual bool isInStorage() const override { return m_location == Location::Storage; } /// Storage references can be pointers or bound references. In general, local variables are of /// pointer type, state variables are bound references. Assignments to pointers or deleting diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index f4d875e77..109481edc 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4243,9 +4243,9 @@ BOOST_AUTO_TEST_CASE(return_string) function get1() returns (string r) { return s; } -// function get2() returns (string r) { -// r = s; -// } + function get2() returns (string r) { + r = s; + } } )"; compileAndRun(sourceCode, 0, "Main"); @@ -4253,8 +4253,8 @@ BOOST_AUTO_TEST_CASE(return_string) bytes args = encodeArgs(u256(0x20), u256(s.length()), s); BOOST_REQUIRE(callContractFunction("set(string)", asString(args)) == encodeArgs()); BOOST_CHECK(callContractFunction("get1()") == args); -// BOOST_CHECK(callContractFunction("get2()") == args); -// BOOST_CHECK(callContractFunction("s()") == args); + BOOST_CHECK(callContractFunction("get2()") == args); + BOOST_CHECK(callContractFunction("s()") == args); } BOOST_AUTO_TEST_SUITE_END()