#include <libsolidity/formal/ArraySlicePredicate.h>
#include <liblangutil/Exceptions.h>
using namespace std;
using namespace solidity;
using namespace solidity::smtutil;
using namespace solidity::frontend;
using namespace solidity::frontend::smt;
map<string, ArraySlicePredicate::SliceData> ArraySlicePredicate::m_slicePredicates;
pair<bool, ArraySlicePredicate::SliceData const&> ArraySlicePredicate::create(SortPointer _sort, EncodingContext& _context)
{
solAssert(_sort->kind == Kind::Tuple, "");
auto tupleSort = dynamic_pointer_cast<TupleSort>(_sort);
solAssert(tupleSort, "");
auto tupleName = tupleSort->name;
if (m_slicePredicates.count(tupleName))
return {true, m_slicePredicates.at(tupleName)};
auto sort = tupleSort->components.at(0);
solAssert(sort->kind == Kind::Array, "");
smt::SymbolicArrayVariable aVar{sort, "a_" + tupleName, _context };
smt::SymbolicArrayVariable bVar{sort, "b_" + tupleName, _context};
smt::SymbolicIntVariable startVar{TypeProvider::uint256(), TypeProvider::uint256(), "start_" + tupleName, _context};
smt::SymbolicIntVariable endVar{TypeProvider::uint256(), TypeProvider::uint256(), "end_" + tupleName, _context };
smt::SymbolicIntVariable iVar{TypeProvider::uint256(), TypeProvider::uint256(), "i_" + tupleName, _context};
vector<SortPointer> domain{sort, sort, startVar.sort(), endVar.sort()};
auto sliceSort = make_shared<FunctionSort>(domain, SortProvider::boolSort);
Predicate const& slice = *Predicate::create(sliceSort, "array_slice_" + tupleName, PredicateType::Custom, _context);
domain.emplace_back(iVar.sort());
auto predSort = make_shared<FunctionSort>(domain, SortProvider::boolSort);
Predicate const& header = *Predicate::create(predSort, "array_slice_header_" + tupleName, PredicateType::Custom, _context);
Predicate const& loop = *Predicate::create(predSort, "array_slice_loop_" + tupleName, PredicateType::Custom, _context);
auto a = aVar.elements();
auto b = bVar.elements();
auto start = startVar.currentValue();
auto end = endVar.currentValue();
auto i = iVar.currentValue();
auto rule1 = smtutil::Expression::implies(
end > start,
header({a, b, start, end, 0})
);
auto rule2 = smtutil::Expression::implies(
header({a, b, start, end, i}) && i >= (end - start),
slice({a, b, start, end})
);
auto rule3 = smtutil::Expression::implies(
header({a, b, start, end, i}) && i >= 0 && i < (end - start),
loop({a, b, start, end, i})
);
auto b_i = smtutil::Expression::select(b, i);
auto a_start_i = smtutil::Expression::select(a, start + i);
auto rule4 = smtutil::Expression::implies(
loop({a, b, start, end, i}) && b_i == a_start_i,
header({a, b, start, end, i + 1})
);
return {false, m_slicePredicates[tupleName] = {
{&slice, &header, &loop},
{move(rule1), move(rule2), move(rule3), move(rule4)}
}};
}