From 518daee5465570714d4fb59bc227c3195c64bdf6 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Tue, 31 Mar 2015 11:07:10 +0200 Subject: [PATCH] some more tests --- libsolidity/CompilerContext.h | 1 + libsolidity/ExpressionCompiler.cpp | 46 +++++++++++++++++++----------- libsolidity/Types.cpp | 22 +++++++------- test/SolidityEndToEndTest.cpp | 39 +++++++++++++++++++++---- 4 files changed, 74 insertions(+), 34 deletions(-) diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h index 87f90d4c4..e752d59b8 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/CompilerContext.h @@ -83,6 +83,7 @@ public: /// Converts an offset relative to the current stack height to a value that can be used later /// with baseToCurrentStackOffset to point to the same stack element. unsigned currentToBaseStackOffset(unsigned _offset) const; + /// @returns pair of slot and byte offset of the value inside this slot. std::pair getStorageLocationOfVariable(Declaration const& _declaration) const; /// Appends a JUMPI instruction to a new tag and @returns the tag diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 59781f821..30cc3c6f8 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -62,8 +62,19 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& unsigned length = 0; TypePointers const& paramTypes = accessorType.getParameterTypes(); - // move arguments to memory - for (TypePointer const& paramType: boost::adaptors::reverse(paramTypes)) + + // to exclude the last key if it is an array + TypePointer finalMappingValueType = _varDecl.getType(); + while (finalMappingValueType->getCategory() == Type::Category::Mapping) + finalMappingValueType = dynamic_cast(*finalMappingValueType).getValueType(); + + bool finalIsArrayType = finalMappingValueType->getCategory() == Type::Category::Array; + TypePointers mappingKeys(paramTypes); + if (finalIsArrayType) + mappingKeys.pop_back(); + + // move mapping arguments to memory + for (TypePointer const& paramType: boost::adaptors::reverse(mappingKeys)) length += CompilerUtils(m_context).storeInMemory(length, *paramType, true); // retrieve the position of the variable @@ -71,20 +82,21 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& m_context << location.first; TypePointer returnType = _varDecl.getType(); - if (ArrayType const* arrayType = dynamic_cast(returnType.get())) + + for (TypePointer const& paramType: mappingKeys) { - (void)arrayType; - } else - for (TypePointer const& paramType: paramTypes) - { - // move offset to memory - CompilerUtils(m_context).storeInMemory(length); - unsigned argLen = paramType->getCalldataEncodedSize(); - length -= argLen; - m_context << u256(argLen + 32) << u256(length) << eth::Instruction::SHA3; + // move offset to memory + CompilerUtils(m_context).storeInMemory(length); + unsigned argLen = paramType->getCalldataEncodedSize(); + length -= argLen; + m_context << u256(argLen + 32) << u256(length) << eth::Instruction::SHA3; - returnType = dynamic_cast(*returnType).getValueType(); - } + returnType = dynamic_cast(*returnType).getValueType(); + } + if (finalMappingValueType->isDynamicallySized()) + { + + } unsigned retSizeOnStack = 0; solAssert(accessorType.getReturnParameterTypes().size() >= 1, ""); @@ -100,7 +112,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& pair const& offsets = structType->getStorageOffsetsOfMember(names[i]); m_context << eth::Instruction::DUP1 << u256(offsets.first) << eth::Instruction::ADD << u256(offsets.second); StorageItem(m_context, *types[i]).retrieveValue(SourceLocation(), true); - solAssert(types[i]->getSizeOnStack() == 1, "Returning struct elements with stack size != 1 not yet implemented."); + solAssert(types[i]->getSizeOnStack() == 1, "Returning struct elements with stack size != 1 is not yet implemented."); m_context << eth::Instruction::SWAP1; retSizeOnStack += types[i]->getSizeOnStack(); } @@ -114,7 +126,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& StorageItem(m_context, *returnType).retrieveValue(SourceLocation(), true); retSizeOnStack = returnType->getSizeOnStack(); } - solAssert(retSizeOnStack <= 15, "Stack too deep."); + solAssert(retSizeOnStack <= 15, "Stack is too deep."); m_context << eth::dupInstruction(retSizeOnStack + 1); m_context.appendJump(eth::AssemblyItem::JumpType::OutOfFunction); } @@ -753,7 +765,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) appendTypeMoveToMemory(IntegerType(256)); m_context << u256(0) << eth::Instruction::SHA3; m_context << u256(0); - setLValueToStorageItem( _indexAccess); + setLValueToStorageItem(_indexAccess); } else if (baseType.getCategory() == Type::Category::Array) { diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 0c80a0f7d..9a5b120b6 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -1002,17 +1002,17 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl): retParamNames.push_back(member.first); retParams.push_back(member.second); } - } else - if (auto arrayType = dynamic_cast(returnType.get())) - { - params.push_back(make_shared(256)); - paramNames.push_back(""); - returnType = arrayType->getBaseType(); - } else - { - retParams.push_back(returnType); - retParamNames.push_back(""); - } + } else if (auto arrayType = dynamic_cast(returnType.get())) + { + params.push_back(make_shared(256)); + paramNames.push_back(""); + returnType = arrayType->getBaseType(); + } + else + { + retParams.push_back(returnType); + retParamNames.push_back(""); + } swap(params, m_parameterTypes); swap(paramNames, m_parameterNames); diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 3c4c2bc0e..1b7f4129c 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -967,16 +967,43 @@ BOOST_AUTO_TEST_CASE(simple_accessor) } BOOST_AUTO_TEST_CASE(array_accessor) +{ + char const* sourceCode = R"( + contract test { + uint[8] data; + uint[] dynamicData; + function test() { + data[2] = 8; + dynamicData.length = 3; + dynamicData[2] = 8; + } + } + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("data(uint256)", 2) == encodeArgs(8)); + BOOST_CHECK(callContractFunction("data(uint256)", 8) == encodeArgs()); + BOOST_CHECK(callContractFunction("dynamicData(uint256)", 2) == encodeArgs(8)); + BOOST_CHECK(callContractFunction("dynamicData(uint256)", 8) == encodeArgs()); +} + +BOOST_AUTO_TEST_CASE(accessors_mapping_for_array) { char const* sourceCode = R"( contract test { - uint[8] datas; - function test() { - datas[2] = 8; - } - })"; + mapping(uint => uint[8]) data; + mapping(uint => uint[]) dynamicData; + function test() { + data[2][2] = 8; + dynamicData[2].length = 3; + dynamicData[2][2] = 8; + } + } + )"; compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("data(2)") == encodeArgs(8)); + BOOST_CHECK(callContractFunction("data(uint256,uint256)", 2, 2) == encodeArgs(8)); + BOOST_CHECK(callContractFunction("data(uint256, 256)", 2, 8) == encodeArgs()); + BOOST_CHECK(callContractFunction("dynamicData(uint256,uint256)", 2, 2) == encodeArgs(8)); + BOOST_CHECK(callContractFunction("dynamicData(uint256,uint256)", 2, 8) == encodeArgs()); } BOOST_AUTO_TEST_CASE(multiple_elementary_accessors)