mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #8639 from ethereum/smt_tuple_sort
[SMTChecker] Add and use tuple sort
This commit is contained in:
commit
accd8d7667
@ -196,6 +196,16 @@ CVC4::Expr CVC4Interface::toCVC4Expr(Expression const& _expr)
|
|||||||
solAssert(sortSort, "");
|
solAssert(sortSort, "");
|
||||||
return m_context.mkConst(CVC4::ArrayStoreAll(cvc4Sort(*sortSort->inner), arguments[1]));
|
return m_context.mkConst(CVC4::ArrayStoreAll(cvc4Sort(*sortSort->inner), arguments[1]));
|
||||||
}
|
}
|
||||||
|
else if (n == "tuple_get")
|
||||||
|
{
|
||||||
|
shared_ptr<TupleSort> tupleSort = std::dynamic_pointer_cast<TupleSort>(_expr.arguments[0].sort);
|
||||||
|
solAssert(tupleSort, "");
|
||||||
|
CVC4::DatatypeType tt = m_context.mkTupleType(cvc4Sort(tupleSort->components));
|
||||||
|
CVC4::Datatype const& dt = tt.getDatatype();
|
||||||
|
size_t index = std::stoi(_expr.arguments[1].name);
|
||||||
|
CVC4::Expr s = dt[0][index].getSelector();
|
||||||
|
return m_context.mkExpr(CVC4::kind::APPLY_SELECTOR, s, arguments[0]);
|
||||||
|
}
|
||||||
|
|
||||||
solAssert(false, "");
|
solAssert(false, "");
|
||||||
}
|
}
|
||||||
@ -229,6 +239,11 @@ CVC4::Type CVC4Interface::cvc4Sort(Sort const& _sort)
|
|||||||
auto const& arraySort = dynamic_cast<ArraySort const&>(_sort);
|
auto const& arraySort = dynamic_cast<ArraySort const&>(_sort);
|
||||||
return m_context.mkArrayType(cvc4Sort(*arraySort.domain), cvc4Sort(*arraySort.range));
|
return m_context.mkArrayType(cvc4Sort(*arraySort.domain), cvc4Sort(*arraySort.range));
|
||||||
}
|
}
|
||||||
|
case Kind::Tuple:
|
||||||
|
{
|
||||||
|
auto const& tupleSort = dynamic_cast<TupleSort const&>(_sort);
|
||||||
|
return m_context.mkTupleType(cvc4Sort(tupleSort.components));
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -296,16 +296,22 @@ void SMTEncoder::endVisit(VariableDeclarationStatement const& _varDecl)
|
|||||||
{
|
{
|
||||||
auto symbTuple = dynamic_pointer_cast<smt::SymbolicTupleVariable>(m_context.expression(*init));
|
auto symbTuple = dynamic_pointer_cast<smt::SymbolicTupleVariable>(m_context.expression(*init));
|
||||||
solAssert(symbTuple, "");
|
solAssert(symbTuple, "");
|
||||||
auto const& components = symbTuple->components();
|
auto const& symbComponents = symbTuple->components();
|
||||||
|
|
||||||
|
auto tupleType = dynamic_cast<TupleType const*>(init->annotation().type);
|
||||||
|
solAssert(tupleType, "");
|
||||||
|
solAssert(tupleType->components().size() == symbTuple->components().size(), "");
|
||||||
|
auto const& components = tupleType->components();
|
||||||
|
|
||||||
auto const& declarations = _varDecl.declarations();
|
auto const& declarations = _varDecl.declarations();
|
||||||
solAssert(components.size() == declarations.size(), "");
|
solAssert(symbComponents.size() == declarations.size(), "");
|
||||||
for (unsigned i = 0; i < declarations.size(); ++i)
|
for (unsigned i = 0; i < declarations.size(); ++i)
|
||||||
if (
|
if (
|
||||||
components.at(i) &&
|
components.at(i) &&
|
||||||
declarations.at(i) &&
|
declarations.at(i) &&
|
||||||
m_context.knownVariable(*declarations.at(i))
|
m_context.knownVariable(*declarations.at(i))
|
||||||
)
|
)
|
||||||
assignment(*declarations.at(i), components.at(i)->currentValue(declarations.at(i)->type()));
|
assignment(*declarations.at(i), symbTuple->component(i, components.at(i), declarations.at(i)->type()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (m_context.knownVariable(*_varDecl.declarations().front()))
|
else if (m_context.knownVariable(*_varDecl.declarations().front()))
|
||||||
@ -354,7 +360,7 @@ void SMTEncoder::endVisit(Assignment const& _assignment)
|
|||||||
{
|
{
|
||||||
auto const& type = _assignment.annotation().type;
|
auto const& type = _assignment.annotation().type;
|
||||||
vector<smt::Expression> rightArguments;
|
vector<smt::Expression> rightArguments;
|
||||||
if (_assignment.rightHandSide().annotation().type->category() == Type::Category::Tuple)
|
if (auto const* tupleTypeRight = dynamic_cast<TupleType const*>(_assignment.rightHandSide().annotation().type))
|
||||||
{
|
{
|
||||||
auto symbTupleLeft = dynamic_pointer_cast<smt::SymbolicTupleVariable>(m_context.expression(_assignment.leftHandSide()));
|
auto symbTupleLeft = dynamic_pointer_cast<smt::SymbolicTupleVariable>(m_context.expression(_assignment.leftHandSide()));
|
||||||
solAssert(symbTupleLeft, "");
|
solAssert(symbTupleLeft, "");
|
||||||
@ -365,17 +371,16 @@ void SMTEncoder::endVisit(Assignment const& _assignment)
|
|||||||
auto const& rightComponents = symbTupleRight->components();
|
auto const& rightComponents = symbTupleRight->components();
|
||||||
solAssert(leftComponents.size() == rightComponents.size(), "");
|
solAssert(leftComponents.size() == rightComponents.size(), "");
|
||||||
|
|
||||||
for (unsigned i = 0; i < leftComponents.size(); ++i)
|
auto tupleTypeLeft = dynamic_cast<TupleType const*>(_assignment.leftHandSide().annotation().type);
|
||||||
{
|
solAssert(tupleTypeLeft, "");
|
||||||
auto const& left = leftComponents.at(i);
|
solAssert(tupleTypeLeft->components().size() == leftComponents.size(), "");
|
||||||
auto const& right = rightComponents.at(i);
|
auto const& typesLeft = tupleTypeLeft->components();
|
||||||
/// Right hand side tuple component cannot be empty.
|
|
||||||
solAssert(right, "");
|
solAssert(tupleTypeRight->components().size() == rightComponents.size(), "");
|
||||||
if (left)
|
auto const& typesRight = tupleTypeRight->components();
|
||||||
rightArguments.push_back(right->currentValue(left->originalType()));
|
|
||||||
else
|
for (unsigned i = 0; i < rightComponents.size(); ++i)
|
||||||
rightArguments.push_back(right->currentValue());
|
rightArguments.push_back(symbTupleRight->component(i, typesRight.at(i), typesLeft.at(i)));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -418,17 +423,16 @@ void SMTEncoder::endVisit(TupleExpression const& _tuple)
|
|||||||
solAssert(symbComponents.size() == tupleComponents->size(), "");
|
solAssert(symbComponents.size() == tupleComponents->size(), "");
|
||||||
for (unsigned i = 0; i < symbComponents.size(); ++i)
|
for (unsigned i = 0; i < symbComponents.size(); ++i)
|
||||||
{
|
{
|
||||||
auto sComponent = symbComponents.at(i);
|
|
||||||
auto tComponent = tupleComponents->at(i);
|
auto tComponent = tupleComponents->at(i);
|
||||||
if (sComponent && tComponent)
|
if (tComponent)
|
||||||
{
|
{
|
||||||
if (auto varDecl = identifierToVariable(*tComponent))
|
if (auto varDecl = identifierToVariable(*tComponent))
|
||||||
m_context.addAssertion(sComponent->currentValue() == currentValue(*varDecl));
|
m_context.addAssertion(symbTuple->component(i) == currentValue(*varDecl));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!m_context.knownExpression(*tComponent))
|
if (!m_context.knownExpression(*tComponent))
|
||||||
createExpr(*tComponent);
|
createExpr(*tComponent);
|
||||||
m_context.addAssertion(sComponent->currentValue() == expr(*tComponent));
|
m_context.addAssertion(symbTuple->component(i) == expr(*tComponent));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -807,13 +811,15 @@ void SMTEncoder::endVisit(Return const& _return)
|
|||||||
{
|
{
|
||||||
auto const& symbTuple = dynamic_pointer_cast<smt::SymbolicTupleVariable>(m_context.expression(*_return.expression()));
|
auto const& symbTuple = dynamic_pointer_cast<smt::SymbolicTupleVariable>(m_context.expression(*_return.expression()));
|
||||||
solAssert(symbTuple, "");
|
solAssert(symbTuple, "");
|
||||||
auto const& components = symbTuple->components();
|
solAssert(symbTuple->components().size() == returnParams.size(), "");
|
||||||
solAssert(components.size() == returnParams.size(), "");
|
|
||||||
|
auto const* tupleType = dynamic_cast<TupleType const*>(_return.expression()->annotation().type);
|
||||||
|
solAssert(tupleType, "");
|
||||||
|
auto const& types = tupleType->components();
|
||||||
|
solAssert(types.size() == returnParams.size(), "");
|
||||||
|
|
||||||
for (unsigned i = 0; i < returnParams.size(); ++i)
|
for (unsigned i = 0; i < returnParams.size(); ++i)
|
||||||
{
|
m_context.addAssertion(symbTuple->component(i, types.at(i), returnParams.at(i)->type()) == m_context.newValue(*returnParams.at(i)));
|
||||||
solAssert(components.at(i), "");
|
|
||||||
m_context.addAssertion(components.at(i)->currentValue(returnParams.at(i)->type()) == m_context.newValue(*returnParams.at(i)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (returnParams.size() == 1)
|
else if (returnParams.size() == 1)
|
||||||
m_context.addAssertion(expr(*_return.expression(), returnParams.front()->type()) == m_context.newValue(*returnParams.front()));
|
m_context.addAssertion(expr(*_return.expression(), returnParams.front()->type()) == m_context.newValue(*returnParams.front()));
|
||||||
@ -1676,14 +1682,10 @@ void SMTEncoder::createReturnedExpressions(FunctionCall const& _funCall)
|
|||||||
solAssert(symbComponents.size() == returnParams.size(), "");
|
solAssert(symbComponents.size() == returnParams.size(), "");
|
||||||
for (unsigned i = 0; i < symbComponents.size(); ++i)
|
for (unsigned i = 0; i < symbComponents.size(); ++i)
|
||||||
{
|
{
|
||||||
auto sComponent = symbComponents.at(i);
|
|
||||||
auto param = returnParams.at(i);
|
auto param = returnParams.at(i);
|
||||||
solAssert(param, "");
|
solAssert(param, "");
|
||||||
if (sComponent)
|
solAssert(m_context.knownVariable(*param), "");
|
||||||
{
|
m_context.addAssertion(symbTuple->component(i) == currentValue(*param));
|
||||||
solAssert(m_context.knownVariable(*param), "");
|
|
||||||
m_context.addAssertion(sComponent->currentValue() == currentValue(*param));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (returnParams.size() == 1)
|
else if (returnParams.size() == 1)
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace solidity;
|
using namespace solidity;
|
||||||
@ -50,6 +51,7 @@ void SMTLib2Interface::reset()
|
|||||||
m_accumulatedOutput.clear();
|
m_accumulatedOutput.clear();
|
||||||
m_accumulatedOutput.emplace_back();
|
m_accumulatedOutput.emplace_back();
|
||||||
m_variables.clear();
|
m_variables.clear();
|
||||||
|
m_userSorts.clear();
|
||||||
write("(set-option :produce-models true)");
|
write("(set-option :produce-models true)");
|
||||||
write("(set-logic ALL)");
|
write("(set-logic ALL)");
|
||||||
}
|
}
|
||||||
@ -145,6 +147,14 @@ string SMTLib2Interface::toSExpr(smt::Expression const& _expr)
|
|||||||
sexpr += "(as const " + toSmtLibSort(*arraySort) + ") ";
|
sexpr += "(as const " + toSmtLibSort(*arraySort) + ") ";
|
||||||
sexpr += toSExpr(_expr.arguments.at(1));
|
sexpr += toSExpr(_expr.arguments.at(1));
|
||||||
}
|
}
|
||||||
|
else if (_expr.name == "tuple_get")
|
||||||
|
{
|
||||||
|
solAssert(_expr.arguments.size() == 2, "");
|
||||||
|
auto tupleSort = dynamic_pointer_cast<TupleSort>(_expr.arguments.at(0).sort);
|
||||||
|
unsigned index = std::stoi(_expr.arguments.at(1).name);
|
||||||
|
solAssert(index < tupleSort->members.size(), "");
|
||||||
|
sexpr += tupleSort->members.at(index) + " " + toSExpr(_expr.arguments.at(0));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sexpr += _expr.name;
|
sexpr += _expr.name;
|
||||||
@ -169,6 +179,22 @@ string SMTLib2Interface::toSmtLibSort(Sort const& _sort)
|
|||||||
solAssert(arraySort.domain && arraySort.range, "");
|
solAssert(arraySort.domain && arraySort.range, "");
|
||||||
return "(Array " + toSmtLibSort(*arraySort.domain) + ' ' + toSmtLibSort(*arraySort.range) + ')';
|
return "(Array " + toSmtLibSort(*arraySort.domain) + ' ' + toSmtLibSort(*arraySort.range) + ')';
|
||||||
}
|
}
|
||||||
|
case Kind::Tuple:
|
||||||
|
{
|
||||||
|
auto const& tupleSort = dynamic_cast<TupleSort const&>(_sort);
|
||||||
|
if (!m_userSorts.count(tupleSort.name))
|
||||||
|
{
|
||||||
|
m_userSorts.insert(tupleSort.name);
|
||||||
|
string decl("(declare-datatypes ((" + tupleSort.name + " 0)) (((" + tupleSort.name);
|
||||||
|
solAssert(tupleSort.members.size() == tupleSort.components.size(), "");
|
||||||
|
for (unsigned i = 0; i < tupleSort.members.size(); ++i)
|
||||||
|
decl += " (" + tupleSort.members.at(i) + " " + toSmtLibSort(*tupleSort.components.at(i)) + ")";
|
||||||
|
decl += "))))";
|
||||||
|
write(decl);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tupleSort.name;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
solAssert(false, "Invalid SMT sort");
|
solAssert(false, "Invalid SMT sort");
|
||||||
}
|
}
|
||||||
|
@ -74,6 +74,7 @@ private:
|
|||||||
|
|
||||||
std::vector<std::string> m_accumulatedOutput;
|
std::vector<std::string> m_accumulatedOutput;
|
||||||
std::map<std::string, SortPointer> m_variables;
|
std::map<std::string, SortPointer> m_variables;
|
||||||
|
std::set<std::string> m_userSorts;
|
||||||
|
|
||||||
std::map<util::h256, std::string> const& m_queryResponses;
|
std::map<util::h256, std::string> const& m_queryResponses;
|
||||||
std::vector<std::string> m_unhandledQueries;
|
std::vector<std::string> m_unhandledQueries;
|
||||||
|
@ -94,7 +94,8 @@ public:
|
|||||||
{"mod", 2},
|
{"mod", 2},
|
||||||
{"select", 2},
|
{"select", 2},
|
||||||
{"store", 3},
|
{"store", 3},
|
||||||
{"const_array", 2}
|
{"const_array", 2},
|
||||||
|
{"tuple_get", 2}
|
||||||
};
|
};
|
||||||
return operatorsArity.count(name) && operatorsArity.at(name) == arguments.size();
|
return operatorsArity.count(name) && operatorsArity.at(name) == arguments.size();
|
||||||
}
|
}
|
||||||
@ -166,6 +167,19 @@ public:
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Expression tuple_get(Expression _tuple, size_t _index)
|
||||||
|
{
|
||||||
|
solAssert(_tuple.sort->kind == Kind::Tuple, "");
|
||||||
|
std::shared_ptr<TupleSort> tupleSort = std::dynamic_pointer_cast<TupleSort>(_tuple.sort);
|
||||||
|
solAssert(tupleSort, "");
|
||||||
|
solAssert(_index < tupleSort->components.size(), "");
|
||||||
|
return Expression(
|
||||||
|
"tuple_get",
|
||||||
|
std::vector<Expression>{std::move(_tuple), Expression(_index)},
|
||||||
|
tupleSort->components.at(_index)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
friend Expression operator!(Expression _a)
|
friend Expression operator!(Expression _a)
|
||||||
{
|
{
|
||||||
return Expression("not", std::move(_a), Kind::Bool);
|
return Expression("not", std::move(_a), Kind::Bool);
|
||||||
|
@ -33,7 +33,8 @@ enum class Kind
|
|||||||
Bool,
|
Bool,
|
||||||
Function,
|
Function,
|
||||||
Array,
|
Array,
|
||||||
Sort
|
Sort,
|
||||||
|
Tuple
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Sort
|
struct Sort
|
||||||
@ -115,6 +116,46 @@ struct SortSort: public Sort
|
|||||||
SortPointer inner;
|
SortPointer inner;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TupleSort: public Sort
|
||||||
|
{
|
||||||
|
TupleSort(
|
||||||
|
std::string _name,
|
||||||
|
std::vector<std::string> _members,
|
||||||
|
std::vector<SortPointer> _components
|
||||||
|
):
|
||||||
|
Sort(Kind::Tuple),
|
||||||
|
name(std::move(_name)),
|
||||||
|
members(std::move(_members)),
|
||||||
|
components(std::move(_components))
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool operator==(Sort const& _other) const override
|
||||||
|
{
|
||||||
|
if (!Sort::operator==(_other))
|
||||||
|
return false;
|
||||||
|
auto _otherTuple = dynamic_cast<TupleSort const*>(&_other);
|
||||||
|
solAssert(_otherTuple, "");
|
||||||
|
if (name != _otherTuple->name)
|
||||||
|
return false;
|
||||||
|
if (members != _otherTuple->members)
|
||||||
|
return false;
|
||||||
|
if (components.size() != _otherTuple->components.size())
|
||||||
|
return false;
|
||||||
|
if (!std::equal(
|
||||||
|
components.begin(),
|
||||||
|
components.end(),
|
||||||
|
_otherTuple->components.begin(),
|
||||||
|
[&](SortPointer _a, SortPointer _b) { return *_a == *_b; }
|
||||||
|
))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string const name;
|
||||||
|
std::vector<std::string> const members;
|
||||||
|
std::vector<SortPointer> const components;
|
||||||
|
};
|
||||||
|
|
||||||
/** Frequently used sorts.*/
|
/** Frequently used sorts.*/
|
||||||
struct SortProvider
|
struct SortProvider
|
||||||
{
|
{
|
||||||
|
@ -75,6 +75,21 @@ SortPointer smtSort(frontend::Type const& _type)
|
|||||||
return make_shared<ArraySort>(SortProvider::intSort, smtSortAbstractFunction(*arrayType->baseType()));
|
return make_shared<ArraySort>(SortProvider::intSort, smtSortAbstractFunction(*arrayType->baseType()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case Kind::Tuple:
|
||||||
|
{
|
||||||
|
auto tupleType = dynamic_cast<frontend::TupleType const*>(&_type);
|
||||||
|
solAssert(tupleType, "");
|
||||||
|
vector<string> members;
|
||||||
|
auto const& tupleName = _type.identifier();
|
||||||
|
auto const& components = tupleType->components();
|
||||||
|
for (unsigned i = 0; i < components.size(); ++i)
|
||||||
|
members.emplace_back(tupleName + "_accessor_" + to_string(i));
|
||||||
|
return make_shared<TupleSort>(
|
||||||
|
tupleName,
|
||||||
|
members,
|
||||||
|
smtSortAbstractFunction(tupleType->components())
|
||||||
|
);
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
// Abstract case.
|
// Abstract case.
|
||||||
return SortProvider::intSort;
|
return SortProvider::intSort;
|
||||||
@ -96,6 +111,17 @@ SortPointer smtSortAbstractFunction(frontend::Type const& _type)
|
|||||||
return smtSort(_type);
|
return smtSort(_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vector<SortPointer> smtSortAbstractFunction(vector<frontend::TypePointer> const& _types)
|
||||||
|
{
|
||||||
|
vector<SortPointer> sorts;
|
||||||
|
for (auto const& type: _types)
|
||||||
|
if (type)
|
||||||
|
sorts.push_back(smtSortAbstractFunction(*type));
|
||||||
|
else
|
||||||
|
sorts.push_back(SortProvider::intSort);
|
||||||
|
return sorts;
|
||||||
|
}
|
||||||
|
|
||||||
Kind smtKind(frontend::Type::Category _category)
|
Kind smtKind(frontend::Type::Category _category)
|
||||||
{
|
{
|
||||||
if (isNumber(_category))
|
if (isNumber(_category))
|
||||||
@ -106,6 +132,8 @@ Kind smtKind(frontend::Type::Category _category)
|
|||||||
return Kind::Function;
|
return Kind::Function;
|
||||||
else if (isMapping(_category) || isArray(_category))
|
else if (isMapping(_category) || isArray(_category))
|
||||||
return Kind::Array;
|
return Kind::Array;
|
||||||
|
else if (isTuple(_category))
|
||||||
|
return Kind::Tuple;
|
||||||
// Abstract case.
|
// Abstract case.
|
||||||
return Kind::Int;
|
return Kind::Int;
|
||||||
}
|
}
|
||||||
@ -350,4 +378,17 @@ void setSymbolicUnknownValue(Expression _expr, frontend::TypePointer const& _typ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
optional<Expression> symbolicTypeConversion(TypePointer _from, TypePointer _to)
|
||||||
|
{
|
||||||
|
if (_to && _from)
|
||||||
|
// StringLiterals are encoded as SMT arrays in the generic case,
|
||||||
|
// but they can also be compared/assigned to fixed bytes, in which
|
||||||
|
// case they'd need to be encoded as numbers.
|
||||||
|
if (auto strType = dynamic_cast<StringLiteralType const*>(_from))
|
||||||
|
if (_to->category() == frontend::Type::Category::FixedBytes)
|
||||||
|
return smt::Expression(u256(toHex(util::asBytes(strType->value()), util::HexPrefix::Add)));
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ std::vector<SortPointer> smtSort(std::vector<frontend::TypePointer> const& _type
|
|||||||
/// If _type has type Function, abstract it to Integer.
|
/// If _type has type Function, abstract it to Integer.
|
||||||
/// Otherwise return smtSort(_type).
|
/// Otherwise return smtSort(_type).
|
||||||
SortPointer smtSortAbstractFunction(frontend::Type const& _type);
|
SortPointer smtSortAbstractFunction(frontend::Type const& _type);
|
||||||
|
std::vector<SortPointer> smtSortAbstractFunction(std::vector<frontend::TypePointer> const& _types);
|
||||||
/// Returns the SMT kind that models the Solidity type type category _category.
|
/// Returns the SMT kind that models the Solidity type type category _category.
|
||||||
Kind smtKind(frontend::Type::Category _category);
|
Kind smtKind(frontend::Type::Category _category);
|
||||||
|
|
||||||
@ -69,4 +70,5 @@ void setSymbolicZeroValue(Expression _expr, frontend::TypePointer const& _type,
|
|||||||
void setSymbolicUnknownValue(SymbolicVariable const& _variable, EncodingContext& _context);
|
void setSymbolicUnknownValue(SymbolicVariable const& _variable, EncodingContext& _context);
|
||||||
void setSymbolicUnknownValue(Expression _expr, frontend::TypePointer const& _type, EncodingContext& _context);
|
void setSymbolicUnknownValue(Expression _expr, frontend::TypePointer const& _type, EncodingContext& _context);
|
||||||
|
|
||||||
|
std::optional<Expression> symbolicTypeConversion(TypePointer _from, TypePointer _to);
|
||||||
}
|
}
|
||||||
|
@ -230,16 +230,9 @@ SymbolicArrayVariable::SymbolicArrayVariable(
|
|||||||
|
|
||||||
smt::Expression SymbolicArrayVariable::currentValue(frontend::TypePointer const& _targetType) const
|
smt::Expression SymbolicArrayVariable::currentValue(frontend::TypePointer const& _targetType) const
|
||||||
{
|
{
|
||||||
if (_targetType)
|
optional<smt::Expression> conversion = symbolicTypeConversion(m_originalType, _targetType);
|
||||||
{
|
if (conversion)
|
||||||
solAssert(m_originalType, "");
|
return *conversion;
|
||||||
// StringLiterals are encoded as SMT arrays in the generic case,
|
|
||||||
// but they can also be compared/assigned to fixed bytes, in which
|
|
||||||
// case they'd need to be encoded as numbers.
|
|
||||||
if (auto strType = dynamic_cast<StringLiteralType const*>(m_originalType))
|
|
||||||
if (_targetType->category() == frontend::Type::Category::FixedBytes)
|
|
||||||
return smt::Expression(u256(toHex(util::asBytes(strType->value()), util::HexPrefix::Add)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return SymbolicVariable::currentValue(_targetType);
|
return SymbolicVariable::currentValue(_targetType);
|
||||||
}
|
}
|
||||||
@ -262,16 +255,34 @@ SymbolicTupleVariable::SymbolicTupleVariable(
|
|||||||
SymbolicVariable(_type, _type, move(_uniqueName), _context)
|
SymbolicVariable(_type, _type, move(_uniqueName), _context)
|
||||||
{
|
{
|
||||||
solAssert(isTuple(m_type->category()), "");
|
solAssert(isTuple(m_type->category()), "");
|
||||||
auto const& tupleType = dynamic_cast<TupleType const&>(*m_type);
|
}
|
||||||
auto const& componentsTypes = tupleType.components();
|
|
||||||
for (unsigned i = 0; i < componentsTypes.size(); ++i)
|
SymbolicTupleVariable::SymbolicTupleVariable(
|
||||||
if (componentsTypes.at(i))
|
SortPointer _sort,
|
||||||
{
|
string _uniqueName,
|
||||||
string componentName = m_uniqueName + "_component_" + to_string(i);
|
EncodingContext& _context
|
||||||
auto result = smt::newSymbolicVariable(*componentsTypes.at(i), componentName, m_context);
|
):
|
||||||
solAssert(result.second, "");
|
SymbolicVariable(move(_sort), move(_uniqueName), _context)
|
||||||
m_components.emplace_back(move(result.second));
|
{
|
||||||
}
|
solAssert(m_sort->kind == Kind::Tuple, "");
|
||||||
else
|
}
|
||||||
m_components.emplace_back(nullptr);
|
|
||||||
|
vector<SortPointer> const& SymbolicTupleVariable::components()
|
||||||
|
{
|
||||||
|
auto tupleSort = dynamic_pointer_cast<TupleSort>(m_sort);
|
||||||
|
solAssert(tupleSort, "");
|
||||||
|
return tupleSort->components;
|
||||||
|
}
|
||||||
|
|
||||||
|
smt::Expression SymbolicTupleVariable::component(
|
||||||
|
size_t _index,
|
||||||
|
TypePointer _fromType,
|
||||||
|
TypePointer _toType
|
||||||
|
)
|
||||||
|
{
|
||||||
|
optional<smt::Expression> conversion = symbolicTypeConversion(_fromType, _toType);
|
||||||
|
if (conversion)
|
||||||
|
return *conversion;
|
||||||
|
|
||||||
|
return smt::Expression::tuple_get(currentValue(), _index);
|
||||||
}
|
}
|
||||||
|
@ -249,14 +249,18 @@ public:
|
|||||||
std::string _uniqueName,
|
std::string _uniqueName,
|
||||||
EncodingContext& _context
|
EncodingContext& _context
|
||||||
);
|
);
|
||||||
|
SymbolicTupleVariable(
|
||||||
|
SortPointer _sort,
|
||||||
|
std::string _uniqueName,
|
||||||
|
EncodingContext& _context
|
||||||
|
);
|
||||||
|
|
||||||
std::vector<std::shared_ptr<SymbolicVariable>> const& components()
|
std::vector<SortPointer> const& components();
|
||||||
{
|
Expression component(
|
||||||
return m_components;
|
size_t _index,
|
||||||
}
|
TypePointer _fromType = nullptr,
|
||||||
|
TypePointer _toType = nullptr
|
||||||
private:
|
);
|
||||||
std::vector<std::shared_ptr<SymbolicVariable>> m_components;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -193,6 +193,11 @@ z3::expr Z3Interface::toZ3Expr(Expression const& _expr)
|
|||||||
solAssert(arraySort && arraySort->domain, "");
|
solAssert(arraySort && arraySort->domain, "");
|
||||||
return z3::const_array(z3Sort(*arraySort->domain), arguments[1]);
|
return z3::const_array(z3Sort(*arraySort->domain), arguments[1]);
|
||||||
}
|
}
|
||||||
|
else if (n == "tuple_get")
|
||||||
|
{
|
||||||
|
size_t index = std::stoi(_expr.arguments[1].name);
|
||||||
|
return z3::func_decl(m_context, Z3_get_tuple_sort_field_decl(m_context, z3Sort(*_expr.arguments[0].sort), index))(arguments[0]);
|
||||||
|
}
|
||||||
|
|
||||||
solAssert(false, "");
|
solAssert(false, "");
|
||||||
}
|
}
|
||||||
@ -217,6 +222,28 @@ z3::sort Z3Interface::z3Sort(Sort const& _sort)
|
|||||||
auto const& arraySort = dynamic_cast<ArraySort const&>(_sort);
|
auto const& arraySort = dynamic_cast<ArraySort const&>(_sort);
|
||||||
return m_context.array_sort(z3Sort(*arraySort.domain), z3Sort(*arraySort.range));
|
return m_context.array_sort(z3Sort(*arraySort.domain), z3Sort(*arraySort.range));
|
||||||
}
|
}
|
||||||
|
case Kind::Tuple:
|
||||||
|
{
|
||||||
|
auto const& tupleSort = dynamic_cast<TupleSort const&>(_sort);
|
||||||
|
vector<char const*> cMembers;
|
||||||
|
for (auto const& member: tupleSort.members)
|
||||||
|
cMembers.emplace_back(member.c_str());
|
||||||
|
/// Using this instead of the function below because with that one
|
||||||
|
/// we can't use `&sorts[0]` here.
|
||||||
|
vector<z3::sort> sorts;
|
||||||
|
for (auto const& sort: tupleSort.components)
|
||||||
|
sorts.push_back(z3Sort(*sort));
|
||||||
|
z3::func_decl_vector projs(m_context);
|
||||||
|
z3::func_decl tupleConstructor = m_context.tuple_sort(
|
||||||
|
tupleSort.name.c_str(),
|
||||||
|
tupleSort.members.size(),
|
||||||
|
&cMembers[0],
|
||||||
|
&sorts[0],
|
||||||
|
projs
|
||||||
|
);
|
||||||
|
return tupleConstructor.range();
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user