diff --git a/AST.cpp b/AST.cpp index ee6e52250..05e2d52e8 100644 --- a/AST.cpp +++ b/AST.cpp @@ -784,8 +784,7 @@ void Expression::expectType(Type const& _expectedType) " is not implicitly convertible to expected type " + _expectedType.toString() + "." - ) - ); + )); } void Expression::requireLValue() diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 786d386d9..f27cf5fe5 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -85,6 +85,10 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& if (auto mappingType = dynamic_cast(returnType.get())) { solAssert(CompilerUtils::freeMemoryPointer >= 0x40, ""); + solAssert( + !paramTypes[i]->isDynamicallySized(), + "Accessors for mapping with dynamically-sized keys not yet implemented." + ); // pop offset m_context << eth::Instruction::POP; // move storage offset to memory. @@ -803,15 +807,30 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) if (baseType.getCategory() == Type::Category::Mapping) { // stack: storage_base_ref - Type const& keyType = *dynamic_cast(baseType).getKeyType(); - m_context << u256(0); // memory position + auto const& mapping = dynamic_cast(baseType); + Type const& keyType = *mapping.getKeyType(); solAssert(_indexAccess.getIndexExpression(), "Index expression expected."); - solAssert(keyType.getCalldataEncodedSize() <= 0x20, "Dynamic keys not yet implemented."); - appendExpressionCopyToMemory(keyType, *_indexAccess.getIndexExpression()); - m_context << eth::Instruction::SWAP1; - solAssert(CompilerUtils::freeMemoryPointer >= 0x40, ""); - utils().storeInMemoryDynamic(IntegerType(256)); - m_context << u256(0) << eth::Instruction::SHA3; + if (keyType.isDynamicallySized()) + { + _indexAccess.getIndexExpression()->accept(*this); + utils().fetchFreeMemoryPointer(); + // stack: base index mem + // note: the following operations must not allocate memory! + utils().encodeToMemory(TypePointers{mapping.getKeyType()}, TypePointers(), false, true); + m_context << eth::Instruction::SWAP1; + utils().storeInMemoryDynamic(IntegerType(256)); + utils().toSizeAfterFreeMemoryPointer(); + } + else + { + m_context << u256(0); // memory position + appendExpressionCopyToMemory(keyType, *_indexAccess.getIndexExpression()); + m_context << eth::Instruction::SWAP1; + solAssert(CompilerUtils::freeMemoryPointer >= 0x40, ""); + utils().storeInMemoryDynamic(IntegerType(256)); + m_context << u256(0); + } + m_context << eth::Instruction::SHA3; m_context << u256(0); setLValueToStorageItem(_indexAccess); } diff --git a/Types.cpp b/Types.cpp index d85c0511f..89ff2134f 100644 --- a/Types.cpp +++ b/Types.cpp @@ -179,6 +179,8 @@ TypePointer Type::fromMapping(ElementaryTypeName& _keyType, TypeName& _valueType BOOST_THROW_EXCEPTION(_valueType.createTypeError("Invalid type name.")); // Convert value type to storage reference. valueType = ReferenceType::copyForLocationIfReference(DataLocation::Storage, valueType); + // Convert key type to memory. + keyType = ReferenceType::copyForLocationIfReference(DataLocation::Memory, keyType); return make_shared(keyType, valueType); }