diff options
Diffstat (limited to 'libsolidity/formal/SolverInterface.h')
-rw-r--r-- | libsolidity/formal/SolverInterface.h | 106 |
1 files changed, 83 insertions, 23 deletions
diff --git a/libsolidity/formal/SolverInterface.h b/libsolidity/formal/SolverInterface.h index df036190..cc8214de 100644 --- a/libsolidity/formal/SolverInterface.h +++ b/libsolidity/formal/SolverInterface.h @@ -45,7 +45,9 @@ enum class CheckResult enum class Kind { Int, - Bool + Bool, + Function, + Array }; struct Sort @@ -53,11 +55,46 @@ struct Sort Sort(Kind _kind): kind(_kind) {} virtual ~Sort() = default; - Kind const kind; bool operator==(Sort const& _other) const { return kind == _other.kind; } + + Kind const kind; }; using SortPointer = std::shared_ptr<Sort>; +struct FunctionSort: public Sort +{ + FunctionSort(std::vector<SortPointer> _domain, SortPointer _codomain): + Sort(Kind::Function), domain(std::move(_domain)), codomain(std::move(_codomain)) {} + bool operator==(FunctionSort const& _other) const + { + if (!std::equal( + domain.begin(), + domain.end(), + _other.domain.begin(), + [&](SortPointer _a, SortPointer _b) { return *_a == *_b; } + )) + return false; + return Sort::operator==(_other) && *codomain == *_other.codomain; + } + + std::vector<SortPointer> domain; + SortPointer codomain; +}; + +struct ArraySort: public Sort +{ + /// _domain is the sort of the indices + /// _range is the sort of the values + ArraySort(SortPointer _domain, SortPointer _range): + Sort(Kind::Array), domain(std::move(_domain)), range(std::move(_range)) {} + bool operator==(ArraySort const& _other) const + { + return Sort::operator==(_other) && *domain == *_other.domain && *range == *_other.range; + } + + SortPointer domain; + SortPointer range; +}; /// C++ representation of an SMTLIB2 expression. class Expression @@ -89,7 +126,9 @@ public: {"+", 2}, {"-", 2}, {"*", 2}, - {"/", 2} + {"/", 2}, + {"select", 2}, + {"store", 3} }; return operatorsArity.count(name) && operatorsArity.at(name) == arguments.size(); } @@ -107,6 +146,36 @@ public: return !std::move(_a) || std::move(_b); } + /// select is the SMT representation of an array index access. + static Expression select(Expression _array, Expression _index) + { + solAssert(_array.sort->kind == Kind::Array, ""); + auto const& arraySort = dynamic_cast<ArraySort const*>(_array.sort.get()); + solAssert(arraySort, ""); + solAssert(*arraySort->domain == *_index.sort, ""); + return Expression( + "select", + std::vector<Expression>{std::move(_array), std::move(_index)}, + arraySort->range + ); + } + + /// store is the SMT representation of an assignment to array index. + /// The function is pure and returns the modified array. + static Expression store(Expression _array, Expression _index, Expression _element) + { + solAssert(_array.sort->kind == Kind::Array, ""); + auto const& arraySort = dynamic_cast<ArraySort const*>(_array.sort.get()); + solAssert(arraySort, ""); + solAssert(*arraySort->domain == *_index.sort, ""); + solAssert(*arraySort->range == *_element.sort, ""); + return Expression( + "store", + std::vector<Expression>{std::move(_array), std::move(_index), std::move(_element)}, + _array.sort + ); + } + friend Expression operator!(Expression _a) { return Expression("not", std::move(_a), Kind::Bool); @@ -162,10 +231,12 @@ public: Expression operator()(std::vector<Expression> _arguments) const { solAssert( - arguments.empty(), + sort->kind == Kind::Function, "Attempted function application to non-function." ); - return Expression(name, std::move(_arguments), sort); + auto fSort = dynamic_cast<FunctionSort const*>(sort.get()); + solAssert(fSort, ""); + return Expression(name, std::move(_arguments), fSort->codomain); } std::string name; @@ -198,26 +269,12 @@ public: virtual void push() = 0; virtual void pop() = 0; - virtual void declareFunction(std::string _name, std::vector<SortPointer> const& _domain, Sort const& _codomain) = 0; - Expression newFunction(std::string _name, std::vector<SortPointer> const& _domain, Sort const& _codomain) + virtual void declareVariable(std::string const& _name, Sort const& _sort) = 0; + Expression newVariable(std::string _name, SortPointer _sort) { - declareFunction(_name, _domain, _codomain); // Subclasses should do something here - return Expression(std::move(_name), {}, _codomain.kind); - } - virtual void declareInteger(std::string _name) = 0; - Expression newInteger(std::string _name) - { - // Subclasses should do something here - declareInteger(_name); - return Expression(std::move(_name), {}, Kind::Int); - } - virtual void declareBool(std::string _name) = 0; - Expression newBool(std::string _name) - { - // Subclasses should do something here - declareBool(_name); - return Expression(std::move(_name), {}, Kind::Bool); + declareVariable(_name, *_sort); + return Expression(std::move(_name), {}, std::move(_sort)); } virtual void addAssertion(Expression const& _expr) = 0; @@ -227,6 +284,9 @@ public: virtual std::pair<CheckResult, std::vector<std::string>> check(std::vector<Expression> const& _expressionsToEvaluate) = 0; + /// @returns a list of queries that the system was not able to respond to. + virtual std::vector<std::string> unhandledQueries() { return {}; } + protected: // SMT query timeout in milliseconds. static int const queryTimeout = 10000; |