Browse Source

Index and length access for dynamic arrays.

cl-refactor
Christian 10 years ago
parent
commit
de537d5de3
  1. 12
      libsolidity/AST.cpp
  2. 18
      libsolidity/ExpressionCompiler.cpp
  3. 29
      test/SolidityEndToEndTest.cpp

12
libsolidity/AST.cpp

@ -603,7 +603,17 @@ void MemberAccess::checkTypeRequirements()
if (!m_type) if (!m_type)
BOOST_THROW_EXCEPTION(createTypeError("Member \"" + *m_memberName + "\" not found or not " BOOST_THROW_EXCEPTION(createTypeError("Member \"" + *m_memberName + "\" not found or not "
"visible in " + type.toString())); "visible in " + type.toString()));
m_isLValue = (type.getCategory() == Type::Category::Struct); // This should probably move somewhere else.
if (type.getCategory() == Type::Category::Struct)
m_isLValue = true;
else if (type.getCategory() == Type::Category::Array)
{
auto const& arrayType(dynamic_cast<ArrayType const&>(type));
m_isLValue = (*m_memberName == "length" &&
arrayType.getLocation() != ArrayType::Location::CallData && arrayType.isDynamicallySized());
}
else
m_isLValue = false;
} }
void IndexAccess::checkTypeRequirements() void IndexAccess::checkTypeRequirements()

18
libsolidity/ExpressionCompiler.cpp

@ -546,7 +546,8 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; m_context << eth::Instruction::SWAP1 << eth::Instruction::POP;
break; break;
case ArrayType::Location::Storage: case ArrayType::Location::Storage:
m_context << eth::Instruction::SLOAD; m_currentLValue = LValue(m_context, LValue::LValueType::Storage, _memberAccess.getType());
m_currentLValue.retrieveValueIfLValueNotRequested(_memberAccess);
break; break;
default: default:
solAssert(false, "Unsupported array location."); solAssert(false, "Unsupported array location.");
@ -583,13 +584,10 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
ArrayType const& arrayType = dynamic_cast<ArrayType const&>(baseType); ArrayType const& arrayType = dynamic_cast<ArrayType const&>(baseType);
solAssert(arrayType.getLocation() == ArrayType::Location::Storage, solAssert(arrayType.getLocation() == ArrayType::Location::Storage,
"TODO: Index acces only implemented for storage arrays."); "TODO: Index acces only implemented for storage arrays.");
solAssert(!arrayType.isDynamicallySized(), solAssert(!arrayType.isByteArray(), "TODO: Index acces not implemented for byte arrays.");
"TODO: Index acces only implemented for fixed-size arrays.");
solAssert(!arrayType.isByteArray(),
"TODO: Index acces not implemented for byte arrays.");
solAssert(_indexAccess.getIndexExpression(), "Index expression expected."); solAssert(_indexAccess.getIndexExpression(), "Index expression expected.");
// TODO: for dynamically-sized arrays, update the length for each write if (arrayType.isDynamicallySized())
// TODO: do we want to check the index? CompilerUtils(m_context).computeHashStatic();
_indexAccess.getIndexExpression()->accept(*this); _indexAccess.getIndexExpression()->accept(*this);
m_context << arrayType.getBaseType()->getStorageSize() << eth::Instruction::MUL m_context << arrayType.getBaseType()->getStorageSize() << eth::Instruction::MUL
<< eth::Instruction::ADD; << eth::Instruction::ADD;
@ -1075,7 +1073,7 @@ void ExpressionCompiler::LValue::retrieveValue(Location const& _location, bool _
{ {
case LValueType::Stack: case LValueType::Stack:
{ {
unsigned stackPos = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset)); unsigned stackPos = m_context->baseToCurrentStackOffset(m_baseStackOffset);
if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location)
<< errinfo_comment("Stack too deep.")); << errinfo_comment("Stack too deep."));
@ -1124,7 +1122,7 @@ void ExpressionCompiler::LValue::storeValue(Type const& _sourceType, Location co
{ {
case LValueType::Stack: case LValueType::Stack:
{ {
unsigned stackDiff = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset)) - m_size + 1; unsigned stackDiff = m_context->baseToCurrentStackOffset(m_baseStackOffset) - m_size + 1;
if (stackDiff > 16) if (stackDiff > 16)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location)
<< errinfo_comment("Stack too deep.")); << errinfo_comment("Stack too deep."));
@ -1227,7 +1225,7 @@ void ExpressionCompiler::LValue::setToZero(Location const& _location) const
{ {
case LValueType::Stack: case LValueType::Stack:
{ {
unsigned stackDiff = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset)); unsigned stackDiff = m_context->baseToCurrentStackOffset(m_baseStackOffset);
if (stackDiff > 16) if (stackDiff > 16)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location)
<< errinfo_comment("Stack too deep.")); << errinfo_comment("Stack too deep."));

29
test/SolidityEndToEndTest.cpp

@ -2694,6 +2694,35 @@ BOOST_AUTO_TEST_CASE(fixed_arrays_in_storage)
BOOST_CHECK(callContractFunction("getLengths()") == encodeArgs(u256(1) << 10, (u256(1) << 10) + 3)); BOOST_CHECK(callContractFunction("getLengths()") == encodeArgs(u256(1) << 10, (u256(1) << 10) + 3));
} }
BOOST_AUTO_TEST_CASE(dynamic_arrays_in_storage)
{
char const* sourceCode = R"(
contract c {
struct Data { uint x; uint y; }
Data[] data;
uint[] ids;
function setIDStatic(uint id) { ids[2] = id; }
function setID(uint index, uint id) { ids[index] = id; }
function setData(uint index, uint x, uint y) { data[index].x = x; data[index].y = y; }
function getID(uint index) returns (uint) { return ids[index]; }
function getData(uint index) returns (uint x, uint y) { x = data[index].x; y = data[index].y; }
function getLengths() returns (uint l1, uint l2) { l1 = data.length; l2 = ids.length; }
function setLengths(uint l1, uint l2) { data.length = l1; ids.length = l2; }
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("setIDStatic(uint256)", 11) == bytes());
BOOST_CHECK(callContractFunction("getID(uint256)", 2) == encodeArgs(11));
BOOST_CHECK(callContractFunction("setID(uint256,uint256)", 7, 8) == bytes());
BOOST_CHECK(callContractFunction("getID(uint256)", 7) == encodeArgs(8));
BOOST_CHECK(callContractFunction("setData(uint256,uint256,uint256)", 7, 8, 9) == bytes());
BOOST_CHECK(callContractFunction("setData(uint256,uint256,uint256)", 8, 10, 11) == bytes());
BOOST_CHECK(callContractFunction("getData(uint256)", 7) == encodeArgs(8, 9));
BOOST_CHECK(callContractFunction("getData(uint256)", 8) == encodeArgs(10, 11));
BOOST_CHECK(callContractFunction("setLengths(uint256,uint256)", 48, 49) == bytes());
BOOST_CHECK(callContractFunction("getLengths()") == encodeArgs(48, 49));
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

Loading…
Cancel
Save