Merge pull request #6831 from ethereum/compoundAssign

[SolYul] Compound assignment
This commit is contained in:
chriseth 2019-05-24 10:34:08 +02:00 committed by GitHub
commit c74e4dba50
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 207 additions and 147 deletions

View File

@ -129,21 +129,34 @@ void IRGeneratorForStatements::endVisit(VariableDeclarationStatement const& _var
bool IRGeneratorForStatements::visit(Assignment const& _assignment) bool IRGeneratorForStatements::visit(Assignment const& _assignment)
{ {
solUnimplementedAssert(_assignment.assignmentOperator() == Token::Assign, "");
_assignment.rightHandSide().accept(*this); _assignment.rightHandSide().accept(*this);
Type const* intermediateType = type(_assignment.rightHandSide()).closestTemporaryType( Type const* intermediateType = type(_assignment.rightHandSide()).closestTemporaryType(
&type(_assignment.leftHandSide()) &type(_assignment.leftHandSide())
); );
string intermediateValue = m_context.newYulVariable(); string value = m_context.newYulVariable();
m_code << "let " << intermediateValue << " := " << expressionAsType(_assignment.rightHandSide(), *intermediateType) << "\n"; m_code << "let " << value << " := " << expressionAsType(_assignment.rightHandSide(), *intermediateType) << "\n";
_assignment.leftHandSide().accept(*this); _assignment.leftHandSide().accept(*this);
solAssert(!!m_currentLValue, "LValue not retrieved."); solAssert(!!m_currentLValue, "LValue not retrieved.");
m_code << m_currentLValue->storeValue(intermediateValue, *intermediateType);
m_currentLValue.reset();
defineExpression(_assignment) << intermediateValue << "\n"; if (_assignment.assignmentOperator() != Token::Assign)
{
solAssert(type(_assignment.leftHandSide()) == *intermediateType, "");
solAssert(intermediateType->isValueType(), "Compound operators only available for value types.");
string leftIntermediate = m_context.newYulVariable();
m_code << "let " << leftIntermediate << " := " << m_currentLValue->retrieveValue() << "\n";
m_code << value << " := " << binaryOperation(
TokenTraits::AssignmentToBinaryOp(_assignment.assignmentOperator()),
*intermediateType,
leftIntermediate,
value
);
}
m_code << m_currentLValue->storeValue(value, *intermediateType);
m_currentLValue.reset();
defineExpression(_assignment) << value << "\n";
return false; return false;
} }
@ -319,27 +332,6 @@ void IRGeneratorForStatements::endVisit(UnaryOperation const& _unaryOperation)
solUnimplementedAssert(false, "Unary operator not yet implemented"); solUnimplementedAssert(false, "Unary operator not yet implemented");
} }
void IRGeneratorForStatements::appendSimpleUnaryOperation(UnaryOperation const& _operation, Expression const& _expr)
{
string func;
if (_operation.getOperator() == Token::Not)
func = "iszero";
else if (_operation.getOperator() == Token::BitNot)
func = "not";
else
solAssert(false, "Invalid Token!");
defineExpression(_operation) <<
m_utils.cleanupFunction(type(_expr)) <<
"(" <<
func <<
"(" <<
m_context.variable(_expr) <<
")" <<
")\n";
}
bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp) bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
{ {
solAssert(!!_binOp.annotation().commonType, ""); solAssert(!!_binOp.annotation().commonType, "");
@ -397,24 +389,10 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
} }
else else
{ {
if (IntegerType const* type = dynamic_cast<IntegerType const*>(commonType)) string left = expressionAsType(_binOp.leftExpression(), *commonType);
{ string right = expressionAsType(_binOp.rightExpression(), *commonType);
solUnimplementedAssert(!type->isSigned(), "");
string left = expressionAsType(_binOp.leftExpression(), *commonType); defineExpression(_binOp) << binaryOperation(_binOp.getOperator(), *commonType, left, right);
string right = expressionAsType(_binOp.rightExpression(), *commonType);
string fun;
if (_binOp.getOperator() == Token::Add)
fun = m_utils.overflowCheckedUIntAddFunction(type->numBits());
else if (_binOp.getOperator() == Token::Sub)
fun = m_utils.overflowCheckedUIntSubFunction();
else if (_binOp.getOperator() == Token::Mul)
fun = m_utils.overflowCheckedUIntMulFunction(type->numBits());
else
solUnimplementedAssert(false, "");
defineExpression(_binOp) << fun << "(" << left << ", " << right << ")\n";
}
else
solUnimplementedAssert(false, "");
} }
return false; return false;
} }
@ -1088,6 +1066,55 @@ ostream& IRGeneratorForStatements::defineExpressionPart(Expression const& _expre
return m_code << "let " << m_context.variablePart(_expression, _part) << " := "; return m_code << "let " << m_context.variablePart(_expression, _part) << " := ";
} }
void IRGeneratorForStatements::appendSimpleUnaryOperation(UnaryOperation const& _operation, Expression const& _expr)
{
string func;
if (_operation.getOperator() == Token::Not)
func = "iszero";
else if (_operation.getOperator() == Token::BitNot)
func = "not";
else
solAssert(false, "Invalid Token!");
defineExpression(_operation) <<
m_utils.cleanupFunction(type(_expr)) <<
"(" <<
func <<
"(" <<
m_context.variable(_expr) <<
")" <<
")\n";
}
string IRGeneratorForStatements::binaryOperation(
langutil::Token _operator,
Type const& _type,
string const& _left,
string const& _right
)
{
if (IntegerType const* type = dynamic_cast<IntegerType const*>(&_type))
{
solUnimplementedAssert(!type->isSigned(), "");
string fun;
if (_operator == Token::Add)
fun = m_utils.overflowCheckedUIntAddFunction(type->numBits());
else if (_operator == Token::Sub)
fun = m_utils.overflowCheckedUIntSubFunction();
else if (_operator == Token::Mul)
fun = m_utils.overflowCheckedUIntMulFunction(type->numBits());
else
solUnimplementedAssert(false, "");
return fun + "(" + _left + ", " + _right + ")\n";
}
else
solUnimplementedAssert(false, "");
return {};
}
void IRGeneratorForStatements::appendAndOrOperatorCode(BinaryOperation const& _binOp) void IRGeneratorForStatements::appendAndOrOperatorCode(BinaryOperation const& _binOp)
{ {
langutil::Token const op = _binOp.getOperator(); langutil::Token const op = _binOp.getOperator();

View File

@ -84,6 +84,14 @@ private:
void appendAndOrOperatorCode(BinaryOperation const& _binOp); void appendAndOrOperatorCode(BinaryOperation const& _binOp);
void appendSimpleUnaryOperation(UnaryOperation const& _operation, Expression const& _expr); void appendSimpleUnaryOperation(UnaryOperation const& _operation, Expression const& _expr);
/// @returns code to perform the given binary operation in the given type on the two values.
std::string binaryOperation(
langutil::Token _op,
Type const& _type,
std::string const& _left,
std::string const& _right
);
void setLValue(Expression const& _expression, std::unique_ptr<IRLValue> _lvalue); void setLValue(Expression const& _expression, std::unique_ptr<IRLValue> _lvalue);
void generateLoop( void generateLoop(
Statement const& _body, Statement const& _body,

View File

@ -1217,9 +1217,11 @@ BOOST_AUTO_TEST_CASE(strings)
} }
} }
)"; )";
compileAndRun(sourceCode); ALSO_VIA_YUL(
ABI_CHECK(callContractFunction("fixedBytes()"), encodeArgs(string("abc\0\xff__", 7))); compileAndRun(sourceCode);
ABI_CHECK(callContractFunction("pipeThrough(bytes2,bool)", string("\0\x02", 2), true), encodeArgs(string("\0\x2", 2), true)); ABI_CHECK(callContractFunction("fixedBytes()"), encodeArgs(string("abc\0\xff__", 7)));
ABI_CHECK(callContractFunction("pipeThrough(bytes2,bool)", string("\0\x02", 2), true), encodeArgs(string("\0\x2", 2), true));
)
} }
BOOST_AUTO_TEST_CASE(inc_dec_operators) BOOST_AUTO_TEST_CASE(inc_dec_operators)
@ -1239,8 +1241,10 @@ BOOST_AUTO_TEST_CASE(inc_dec_operators)
} }
} }
)"; )";
compileAndRun(sourceCode); ALSO_VIA_YUL(
ABI_CHECK(callContractFunction("f()"), encodeArgs(0x53866)); compileAndRun(sourceCode);
ABI_CHECK(callContractFunction("f()"), encodeArgs(0x53866));
)
} }
BOOST_AUTO_TEST_CASE(bytes_comparison) BOOST_AUTO_TEST_CASE(bytes_comparison)
@ -1255,8 +1259,10 @@ BOOST_AUTO_TEST_CASE(bytes_comparison)
} }
} }
)"; )";
compileAndRun(sourceCode); ALSO_VIA_YUL(
ABI_CHECK(callContractFunction("f()"), encodeArgs(true)); compileAndRun(sourceCode);
ABI_CHECK(callContractFunction("f()"), encodeArgs(true));
)
} }
BOOST_AUTO_TEST_CASE(state_smoke_test) BOOST_AUTO_TEST_CASE(state_smoke_test)
@ -1275,15 +1281,17 @@ BOOST_AUTO_TEST_CASE(state_smoke_test)
} }
} }
)"; )";
compileAndRun(sourceCode); ALSO_VIA_YUL(
ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x00)), encodeArgs(0)); compileAndRun(sourceCode);
ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x01)), encodeArgs(0)); ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x00)), encodeArgs(0));
ABI_CHECK(callContractFunction("set(uint8,uint256)", uint8_t(0x00), 0x1234), encodeArgs()); ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x01)), encodeArgs(0));
ABI_CHECK(callContractFunction("set(uint8,uint256)", uint8_t(0x01), 0x8765), encodeArgs()); ABI_CHECK(callContractFunction("set(uint8,uint256)", uint8_t(0x00), 0x1234), encodeArgs());
ABI_CHECK(callContractFunction("get(uint8)", uint8_t( 0x00)), encodeArgs(0x1234)); ABI_CHECK(callContractFunction("set(uint8,uint256)", uint8_t(0x01), 0x8765), encodeArgs());
ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x01)), encodeArgs(0x8765)); ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x00)), encodeArgs(0x1234));
ABI_CHECK(callContractFunction("set(uint8,uint256)", uint8_t(0x00), 0x3), encodeArgs()); ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x01)), encodeArgs(0x8765));
ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x00)), encodeArgs(0x3)); ABI_CHECK(callContractFunction("set(uint8,uint256)", uint8_t(0x00), 0x3), encodeArgs());
ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x00)), encodeArgs(0x3));
)
} }
BOOST_AUTO_TEST_CASE(compound_assign) BOOST_AUTO_TEST_CASE(compound_assign)
@ -1301,26 +1309,28 @@ BOOST_AUTO_TEST_CASE(compound_assign)
} }
} }
)"; )";
compileAndRun(sourceCode); ALSO_VIA_YUL(
compileAndRun(sourceCode);
u256 value1; u256 value1;
u256 value2; u256 value2;
auto f = [&](u256 const& _x, u256 const& _y) -> u256 auto f = [&](u256 const& _x, u256 const& _y) -> u256
{ {
u256 value3 = _y; u256 value3 = _y;
value1 += _x; value1 += _x;
value3 *= _x; value3 *= _x;
value2 *= value3 + value1; value2 *= value3 + value1;
return value2 += 7; return value2 += 7;
}; };
testContractAgainstCpp("f(uint256,uint256)", f, u256(0), u256(6)); testContractAgainstCpp("f(uint256,uint256)", f, u256(0), u256(6));
testContractAgainstCpp("f(uint256,uint256)", f, u256(1), u256(3)); testContractAgainstCpp("f(uint256,uint256)", f, u256(1), u256(3));
testContractAgainstCpp("f(uint256,uint256)", f, u256(2), u256(25)); testContractAgainstCpp("f(uint256,uint256)", f, u256(2), u256(25));
testContractAgainstCpp("f(uint256,uint256)", f, u256(3), u256(69)); testContractAgainstCpp("f(uint256,uint256)", f, u256(3), u256(69));
testContractAgainstCpp("f(uint256,uint256)", f, u256(4), u256(84)); testContractAgainstCpp("f(uint256,uint256)", f, u256(4), u256(84));
testContractAgainstCpp("f(uint256,uint256)", f, u256(5), u256(2)); testContractAgainstCpp("f(uint256,uint256)", f, u256(5), u256(2));
testContractAgainstCpp("f(uint256,uint256)", f, u256(6), u256(51)); testContractAgainstCpp("f(uint256,uint256)", f, u256(6), u256(51));
testContractAgainstCpp("f(uint256,uint256)", f, u256(7), u256(48)); testContractAgainstCpp("f(uint256,uint256)", f, u256(7), u256(48));
)
} }
BOOST_AUTO_TEST_CASE(simple_mapping) BOOST_AUTO_TEST_CASE(simple_mapping)
@ -1336,23 +1346,25 @@ BOOST_AUTO_TEST_CASE(simple_mapping)
} }
} }
)"; )";
compileAndRun(sourceCode);
ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0)), encodeArgs(uint8_t(0x00))); ALSO_VIA_YUL(
ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x01)), encodeArgs(uint8_t(0x00))); compileAndRun(sourceCode);
ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0xa7)), encodeArgs(uint8_t(0x00))); ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0)), encodeArgs(uint8_t(0x00)));
callContractFunction("set(uint8,uint8)", uint8_t(0x01), uint8_t(0xa1)); ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x01)), encodeArgs(uint8_t(0x00)));
ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x00)), encodeArgs(uint8_t(0x00))); ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0xa7)), encodeArgs(uint8_t(0x00)));
ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x01)), encodeArgs(uint8_t(0xa1))); callContractFunction("set(uint8,uint8)", uint8_t(0x01), uint8_t(0xa1));
ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0xa7)), encodeArgs(uint8_t(0x00))); ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x00)), encodeArgs(uint8_t(0x00)));
callContractFunction("set(uint8,uint8)", uint8_t(0x00), uint8_t(0xef)); ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x01)), encodeArgs(uint8_t(0xa1)));
ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x00)), encodeArgs(uint8_t(0xef))); ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0xa7)), encodeArgs(uint8_t(0x00)));
ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x01)), encodeArgs(uint8_t(0xa1))); callContractFunction("set(uint8,uint8)", uint8_t(0x00), uint8_t(0xef));
ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0xa7)), encodeArgs(uint8_t(0x00))); ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x00)), encodeArgs(uint8_t(0xef)));
callContractFunction("set(uint8,uint8)", uint8_t(0x01), uint8_t(0x05)); ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x01)), encodeArgs(uint8_t(0xa1)));
ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x00)), encodeArgs(uint8_t(0xef))); ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0xa7)), encodeArgs(uint8_t(0x00)));
ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x01)), encodeArgs(uint8_t(0x05))); callContractFunction("set(uint8,uint8)", uint8_t(0x01), uint8_t(0x05));
ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0xa7)), encodeArgs(uint8_t(0x00))); ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x00)), encodeArgs(uint8_t(0xef)));
ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0x01)), encodeArgs(uint8_t(0x05)));
ABI_CHECK(callContractFunction("get(uint8)", uint8_t(0xa7)), encodeArgs(uint8_t(0x00)));
)
} }
BOOST_AUTO_TEST_CASE(mapping_state) BOOST_AUTO_TEST_CASE(mapping_state)
@ -1376,7 +1388,6 @@ BOOST_AUTO_TEST_CASE(mapping_state)
} }
} }
)"; )";
compileAndRun(sourceCode);
class Ballot class Ballot
{ {
public: public:
@ -1393,43 +1404,47 @@ BOOST_AUTO_TEST_CASE(mapping_state)
map<u160, bool> m_canVote; map<u160, bool> m_canVote;
map<u160, u256> m_voteCount; map<u160, u256> m_voteCount;
map<u160, bool> m_voted; map<u160, bool> m_voted;
} ballot; };
ALSO_VIA_YUL(
compileAndRun(sourceCode);
Ballot ballot;
auto getVoteCount = bind(&Ballot::getVoteCount, &ballot, _1); auto getVoteCount = bind(&Ballot::getVoteCount, &ballot, _1);
auto grantVoteRight = bind(&Ballot::grantVoteRight, &ballot, _1); auto grantVoteRight = bind(&Ballot::grantVoteRight, &ballot, _1);
auto vote = bind(&Ballot::vote, &ballot, _1, _2); auto vote = bind(&Ballot::vote, &ballot, _1, _2);
testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(0)); testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(0));
testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(1)); testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(1));
testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(2)); testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(2));
// voting without vote right should be rejected // voting without vote right should be rejected
testContractAgainstCpp("vote(address,address)", vote, u160(0), u160(2)); testContractAgainstCpp("vote(address,address)", vote, u160(0), u160(2));
testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(0)); testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(0));
testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(1)); testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(1));
testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(2)); testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(2));
// grant vote rights // grant vote rights
testContractAgainstCpp("grantVoteRight(address)", grantVoteRight, u160(0)); testContractAgainstCpp("grantVoteRight(address)", grantVoteRight, u160(0));
testContractAgainstCpp("grantVoteRight(address)", grantVoteRight, u160(1)); testContractAgainstCpp("grantVoteRight(address)", grantVoteRight, u160(1));
// vote, should increase 2's vote count // vote, should increase 2's vote count
testContractAgainstCpp("vote(address,address)", vote, u160(0), u160(2)); testContractAgainstCpp("vote(address,address)", vote, u160(0), u160(2));
testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(0)); testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(0));
testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(1)); testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(1));
testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(2)); testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(2));
// vote again, should be rejected // vote again, should be rejected
testContractAgainstCpp("vote(address,address)", vote, u160(0), u160(1)); testContractAgainstCpp("vote(address,address)", vote, u160(0), u160(1));
testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(0)); testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(0));
testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(1)); testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(1));
testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(2)); testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(2));
// vote without right to vote // vote without right to vote
testContractAgainstCpp("vote(address,address)", vote, u160(2), u160(1)); testContractAgainstCpp("vote(address,address)", vote, u160(2), u160(1));
testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(0)); testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(0));
testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(1)); testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(1));
testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(2)); testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(2));
// grant vote right and now vote again // grant vote right and now vote again
testContractAgainstCpp("grantVoteRight(address)", grantVoteRight, u160(2)); testContractAgainstCpp("grantVoteRight(address)", grantVoteRight, u160(2));
testContractAgainstCpp("vote(address,address)", vote, u160(2), u160(1)); testContractAgainstCpp("vote(address,address)", vote, u160(2), u160(1));
testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(0)); testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(0));
testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(1)); testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(1));
testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(2)); testContractAgainstCpp("getVoteCount(address)", getVoteCount, u160(2));
)
} }
BOOST_AUTO_TEST_CASE(mapping_state_inc_dec) BOOST_AUTO_TEST_CASE(mapping_state_inc_dec)
@ -1443,13 +1458,13 @@ BOOST_AUTO_TEST_CASE(mapping_state_inc_dec)
if (x > 0) table[++value] = 8; if (x > 0) table[++value] = 8;
if (x > 1) value--; if (x > 1) value--;
if (x > 2) table[value]++; if (x > 2) table[value]++;
table[value] += 10;
return --table[value++]; return --table[value++];
} }
} }
)"; )";
compileAndRun(sourceCode);
u256 value = 0; u256 value;
map<u256, u256> table; map<u256, u256> table;
auto f = [&](u256 const& _x) -> u256 auto f = [&](u256 const& _x) -> u256
{ {
@ -1460,9 +1475,16 @@ BOOST_AUTO_TEST_CASE(mapping_state_inc_dec)
value --; value --;
if (_x > 2) if (_x > 2)
table[value]++; table[value]++;
table[value] += 10;
return --table[value++]; return --table[value++];
}; };
testContractAgainstCppOnRange("f(uint256)", f, 0, 5); ALSO_VIA_YUL(
compileAndRun(sourceCode);
value = 0;
table.clear();
testContractAgainstCppOnRange("f(uint256)", f, 0, 5);
)
} }
BOOST_AUTO_TEST_CASE(multi_level_mapping) BOOST_AUTO_TEST_CASE(multi_level_mapping)
@ -1476,22 +1498,25 @@ BOOST_AUTO_TEST_CASE(multi_level_mapping)
} }
} }
)"; )";
compileAndRun(sourceCode);
map<u256, map<u256, u256>> table; map<u256, map<u256, u256>> table;
auto f = [&](u256 const& _x, u256 const& _y, u256 const& _z) -> u256 auto f = [&](u256 const& _x, u256 const& _y, u256 const& _z) -> u256
{ {
if (_z == 0) return table[_x][_y]; if (_z == 0) return table[_x][_y];
else return table[_x][_y] = _z; else return table[_x][_y] = _z;
}; };
testContractAgainstCpp("f(uint256,uint256,uint256)", f, u256(4), u256(5), u256(0)); ALSO_VIA_YUL(
testContractAgainstCpp("f(uint256,uint256,uint256)", f, u256(5), u256(4), u256(0)); compileAndRun(sourceCode);
testContractAgainstCpp("f(uint256,uint256,uint256)", f, u256(4), u256(5), u256(9)); table.clear();
testContractAgainstCpp("f(uint256,uint256,uint256)", f, u256(4), u256(5), u256(0));
testContractAgainstCpp("f(uint256,uint256,uint256)", f, u256(5), u256(4), u256(0)); testContractAgainstCpp("f(uint256,uint256,uint256)", f, u256(4), u256(5), u256(0));
testContractAgainstCpp("f(uint256,uint256,uint256)", f, u256(5), u256(4), u256(7)); testContractAgainstCpp("f(uint256,uint256,uint256)", f, u256(5), u256(4), u256(0));
testContractAgainstCpp("f(uint256,uint256,uint256)", f, u256(4), u256(5), u256(0)); testContractAgainstCpp("f(uint256,uint256,uint256)", f, u256(4), u256(5), u256(9));
testContractAgainstCpp("f(uint256,uint256,uint256)", f, u256(5), u256(4), u256(0)); testContractAgainstCpp("f(uint256,uint256,uint256)", f, u256(4), u256(5), u256(0));
testContractAgainstCpp("f(uint256,uint256,uint256)", f, u256(5), u256(4), u256(0));
testContractAgainstCpp("f(uint256,uint256,uint256)", f, u256(5), u256(4), u256(7));
testContractAgainstCpp("f(uint256,uint256,uint256)", f, u256(4), u256(5), u256(0));
testContractAgainstCpp("f(uint256,uint256,uint256)", f, u256(5), u256(4), u256(0));
)
} }
BOOST_AUTO_TEST_CASE(mapping_local_assignment) BOOST_AUTO_TEST_CASE(mapping_local_assignment)