diff --git a/CompilerContext.h b/CompilerContext.h index 87f90d4c4..e752d59b8 100644 --- a/CompilerContext.h +++ b/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/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 59781f821..30cc3c6f8 100644 --- a/ExpressionCompiler.cpp +++ b/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())) - { - (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; - returnType = dynamic_cast(*returnType).getValueType(); - } + for (TypePointer const& paramType: mappingKeys) + { + // 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(); + } + 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/Types.cpp b/Types.cpp index 0c80a0f7d..9a5b120b6 100644 --- a/Types.cpp +++ b/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);