mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Support arithmetic compound assignment operators
This commit is contained in:
parent
ecbf36f271
commit
15269067b5
@ -4,6 +4,7 @@ Language Features:
|
|||||||
|
|
||||||
|
|
||||||
Compiler Features:
|
Compiler Features:
|
||||||
|
* SMTChecker: Support arithmetic compound assignment operators.
|
||||||
* Yul: Adds break and continue keywords to for-loop syntax.
|
* Yul: Adds break and continue keywords to for-loop syntax.
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include <boost/range/adaptor/map.hpp>
|
#include <boost/range/adaptor/map.hpp>
|
||||||
#include <boost/range/adaptors.hpp>
|
#include <boost/range/adaptors.hpp>
|
||||||
#include <boost/algorithm/string/replace.hpp>
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace dev;
|
using namespace dev;
|
||||||
@ -333,27 +334,59 @@ void SMTChecker::endVisit(VariableDeclarationStatement const& _varDecl)
|
|||||||
|
|
||||||
void SMTChecker::endVisit(Assignment const& _assignment)
|
void SMTChecker::endVisit(Assignment const& _assignment)
|
||||||
{
|
{
|
||||||
if (_assignment.assignmentOperator() != Token::Assign)
|
static map<Token, Token> const compoundToArithmetic{
|
||||||
|
{Token::AssignAdd, Token::Add},
|
||||||
|
{Token::AssignSub, Token::Sub},
|
||||||
|
{Token::AssignMul, Token::Mul},
|
||||||
|
{Token::AssignDiv, Token::Div}
|
||||||
|
};
|
||||||
|
Token op = _assignment.assignmentOperator();
|
||||||
|
if (op != Token::Assign && !compoundToArithmetic.count(op))
|
||||||
m_errorReporter.warning(
|
m_errorReporter.warning(
|
||||||
_assignment.location(),
|
_assignment.location(),
|
||||||
"Assertion checker does not yet implement compound assignment."
|
"Assertion checker does not yet implement this assignment operator."
|
||||||
);
|
);
|
||||||
else if (!isSupportedType(_assignment.annotation().type->category()))
|
else if (!isSupportedType(_assignment.annotation().type->category()))
|
||||||
m_errorReporter.warning(
|
m_errorReporter.warning(
|
||||||
_assignment.location(),
|
_assignment.location(),
|
||||||
"Assertion checker does not yet implement type " + _assignment.annotation().type->toString()
|
"Assertion checker does not yet implement type " + _assignment.annotation().type->toString()
|
||||||
);
|
);
|
||||||
else if (Identifier const* identifier = dynamic_cast<Identifier const*>(&_assignment.leftHandSide()))
|
else if (
|
||||||
|
dynamic_cast<Identifier const*>(&_assignment.leftHandSide()) ||
|
||||||
|
dynamic_cast<IndexAccess const*>(&_assignment.leftHandSide())
|
||||||
|
)
|
||||||
{
|
{
|
||||||
VariableDeclaration const& decl = dynamic_cast<VariableDeclaration const&>(*identifier->annotation().referencedDeclaration);
|
boost::optional<smt::Expression> leftHandSide;
|
||||||
solAssert(knownVariable(decl), "");
|
VariableDeclaration const* decl = nullptr;
|
||||||
assignment(decl, _assignment.rightHandSide(), _assignment.location());
|
auto identifier = dynamic_cast<Identifier const*>(&_assignment.leftHandSide());
|
||||||
defineExpr(_assignment, expr(_assignment.rightHandSide()));
|
if (identifier)
|
||||||
}
|
{
|
||||||
else if (dynamic_cast<IndexAccess const*>(&_assignment.leftHandSide()))
|
decl = dynamic_cast<VariableDeclaration const*>(identifier->annotation().referencedDeclaration);
|
||||||
{
|
solAssert(decl, "");
|
||||||
arrayIndexAssignment(_assignment);
|
solAssert(knownVariable(*decl), "");
|
||||||
defineExpr(_assignment, expr(_assignment.rightHandSide()));
|
leftHandSide = currentValue(*decl);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
leftHandSide = expr(_assignment.leftHandSide());
|
||||||
|
|
||||||
|
solAssert(leftHandSide, "");
|
||||||
|
smt::Expression rightHandSide =
|
||||||
|
compoundToArithmetic.count(op) ?
|
||||||
|
arithmeticOperation(
|
||||||
|
compoundToArithmetic.at(op),
|
||||||
|
*leftHandSide,
|
||||||
|
expr(_assignment.rightHandSide()),
|
||||||
|
_assignment.annotation().type,
|
||||||
|
_assignment.location()
|
||||||
|
) :
|
||||||
|
expr(_assignment.rightHandSide())
|
||||||
|
;
|
||||||
|
defineExpr(_assignment, rightHandSide);
|
||||||
|
|
||||||
|
if (identifier)
|
||||||
|
assignment(*decl, _assignment, _assignment.location());
|
||||||
|
else
|
||||||
|
arrayIndexAssignment(_assignment, expr(_assignment));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_errorReporter.warning(
|
m_errorReporter.warning(
|
||||||
@ -890,7 +923,7 @@ void SMTChecker::arrayAssignment()
|
|||||||
m_arrayAssignmentHappened = true;
|
m_arrayAssignmentHappened = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMTChecker::arrayIndexAssignment(Assignment const& _assignment)
|
void SMTChecker::arrayIndexAssignment(Assignment const& _assignment, smt::Expression const& _rightHandSide)
|
||||||
{
|
{
|
||||||
auto const& indexAccess = dynamic_cast<IndexAccess const&>(_assignment.leftHandSide());
|
auto const& indexAccess = dynamic_cast<IndexAccess const&>(_assignment.leftHandSide());
|
||||||
if (auto const& id = dynamic_cast<Identifier const*>(&indexAccess.baseExpression()))
|
if (auto const& id = dynamic_cast<Identifier const*>(&indexAccess.baseExpression()))
|
||||||
@ -930,7 +963,7 @@ void SMTChecker::arrayIndexAssignment(Assignment const& _assignment)
|
|||||||
smt::Expression store = smt::Expression::store(
|
smt::Expression store = smt::Expression::store(
|
||||||
m_variables[&varDecl]->currentValue(),
|
m_variables[&varDecl]->currentValue(),
|
||||||
expr(*indexAccess.indexExpression()),
|
expr(*indexAccess.indexExpression()),
|
||||||
expr(_assignment.rightHandSide())
|
_rightHandSide
|
||||||
);
|
);
|
||||||
m_interface->addAssertion(newValue(varDecl) == store);
|
m_interface->addAssertion(newValue(varDecl) == store);
|
||||||
// Update the SMT select value after the assignment,
|
// Update the SMT select value after the assignment,
|
||||||
|
@ -123,7 +123,7 @@ private:
|
|||||||
/// while aliasing is not supported.
|
/// while aliasing is not supported.
|
||||||
void arrayAssignment();
|
void arrayAssignment();
|
||||||
/// Handles assignment to SMT array index.
|
/// Handles assignment to SMT array index.
|
||||||
void arrayIndexAssignment(Assignment const& _assignment);
|
void arrayIndexAssignment(Assignment const& _assignment, smt::Expression const& _rightHandSide);
|
||||||
|
|
||||||
/// Division expression in the given type. Requires special treatment because
|
/// Division expression in the given type. Requires special treatment because
|
||||||
/// of rounding for signed division.
|
/// of rounding for signed division.
|
||||||
|
Loading…
Reference in New Issue
Block a user