mirror of
https://github.com/Z3Prover/z3
synced 2026-06-12 03:45:38 +00:00
fix crashes when using replace_all
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
64e7f29533
commit
0bcdca787f
5 changed files with 53 additions and 38 deletions
|
|
@ -364,6 +364,13 @@ namespace recfun {
|
||||||
return alloc(def, m(), m_fid, name, n, domain, range, is_generated);
|
return alloc(def, m(), m_fid, name, n, domain, range, is_generated);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func_decl *util::find_def_decl(symbol const &name, unsigned n, sort *const *params, sort *range, bool is_generated) {
|
||||||
|
def d(m_manager, m_fid, name, n, params, range, is_generated);
|
||||||
|
if (m_plugin->has_def(d.get_decl()))
|
||||||
|
return d.get_decl();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void util::set_definition(replace& subst, promise_def & d, bool is_macro, unsigned n_vars, var * const * vars, expr * rhs) {
|
void util::set_definition(replace& subst, promise_def & d, bool is_macro, unsigned n_vars, var * const * vars, expr * rhs) {
|
||||||
expr_ref rhs1(rhs, m());
|
expr_ref rhs1(rhs, m());
|
||||||
if (!is_macro)
|
if (!is_macro)
|
||||||
|
|
@ -551,6 +558,7 @@ namespace recfun {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
expr_ref plugin::redirect_ite(replace& subst, unsigned n, var * const* vars, expr * e) {
|
expr_ref plugin::redirect_ite(replace& subst, unsigned n, var * const* vars, expr * e) {
|
||||||
expr_ref result(e, m());
|
expr_ref result(e, m());
|
||||||
util u(m());
|
util u(m());
|
||||||
|
|
|
||||||
|
|
@ -211,6 +211,7 @@ namespace recfun {
|
||||||
case_def& get_case_def(func_decl* f) { SASSERT(has_case_def(f)); return *(m_case_defs[f]); }
|
case_def& get_case_def(func_decl* f) { SASSERT(has_case_def(f)); return *(m_case_defs[f]); }
|
||||||
bool is_defined(func_decl* f) {return has_case_def(f) && !get_def(f).get_cases().empty(); }
|
bool is_defined(func_decl* f) {return has_case_def(f) && !get_def(f).get_cases().empty(); }
|
||||||
|
|
||||||
|
|
||||||
func_decl_ref_vector get_rec_funs() {
|
func_decl_ref_vector get_rec_funs() {
|
||||||
func_decl_ref_vector result(m());
|
func_decl_ref_vector result(m());
|
||||||
for (auto& kv : m_defs) result.push_back(kv.m_key);
|
for (auto& kv : m_defs) result.push_back(kv.m_key);
|
||||||
|
|
@ -250,7 +251,7 @@ namespace recfun {
|
||||||
bool is_num_rounds(expr * e) const { return is_app_of(e, m_fid, OP_NUM_ROUNDS); }
|
bool is_num_rounds(expr * e) const { return is_app_of(e, m_fid, OP_NUM_ROUNDS); }
|
||||||
bool owns_app(app * e) const { return e->get_family_id() == m_fid; }
|
bool owns_app(app * e) const { return e->get_family_id() == m_fid; }
|
||||||
bool contains_def(expr* e); // expression contains a def
|
bool contains_def(expr* e); // expression contains a def
|
||||||
|
func_decl *find_def_decl(symbol const &name, unsigned n, sort *const *params, sort *range, bool is_generated);
|
||||||
|
|
||||||
//<! don't use native theory if recursive function declarations are not populated with defs
|
//<! don't use native theory if recursive function declarations are not populated with defs
|
||||||
bool has_defs() const { return m_plugin->has_defs(); }
|
bool has_defs() const { return m_plugin->has_defs(); }
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,6 @@ namespace seq {
|
||||||
a(m),
|
a(m),
|
||||||
seq(m),
|
seq(m),
|
||||||
m_sk(m, r),
|
m_sk(m, r),
|
||||||
m_not_contains(m),
|
|
||||||
m_clause(m),
|
m_clause(m),
|
||||||
m_trail(m)
|
m_trail(m)
|
||||||
{}
|
{}
|
||||||
|
|
@ -1104,37 +1103,41 @@ namespace seq {
|
||||||
VERIFY(seq.str.is_replace_all(r, s, p, t));
|
VERIFY(seq.str.is_replace_all(r, s, p, t));
|
||||||
recfun::util rec(m);
|
recfun::util rec(m);
|
||||||
recfun::decl::plugin& plugin = rec.get_plugin();
|
recfun::decl::plugin& plugin = rec.get_plugin();
|
||||||
recfun_replace replace(m);
|
|
||||||
sort* srt = s->get_sort();
|
sort* srt = s->get_sort();
|
||||||
sort* domain[4] = { srt, srt, srt, srt };
|
sort* domain[4] = { srt, srt, srt, srt };
|
||||||
auto d = plugin.ensure_def(symbol("ra"), 4, domain, m.mk_bool_sort(), true);
|
auto ra = rec.find_def_decl(symbol("ra"), 4, domain, m.mk_bool_sort(), true);
|
||||||
func_decl* ra = d.get_def()->get_decl();
|
|
||||||
// vars: vs=var(3), vp=var(2), vt=var(1), vr=var(0)
|
if (!ra) {
|
||||||
var_ref vs(m.mk_var(3, srt), m);
|
recfun_replace replace(m);
|
||||||
var_ref vp(m.mk_var(2, srt), m);
|
auto d = plugin.ensure_def(symbol("ra"), 4, domain, m.mk_bool_sort(), true);
|
||||||
var_ref vt(m.mk_var(1, srt), m);
|
ra = d.get_def()->get_decl();
|
||||||
var_ref vr(m.mk_var(0, srt), m);
|
// vars: vs=var(3), vp=var(2), vt=var(1), vr=var(0)
|
||||||
var* vars[4] = { vs, vp, vt, vr };
|
var_ref vs(m.mk_var(3, srt), m);
|
||||||
// base case: empty s or empty p -> r = s (no replacements)
|
var_ref vp(m.mk_var(2, srt), m);
|
||||||
expr_ref test1(m.mk_or(seq.str.mk_is_empty(vs), seq.str.mk_is_empty(vp)), m);
|
var_ref vt(m.mk_var(1, srt), m);
|
||||||
expr_ref branch1(m.mk_eq(vr, vs), m);
|
var_ref vr(m.mk_var(0, srt), m);
|
||||||
// match case: prefix(p, s) -> s = p ++ s_tail, r = t ++ r_tail, ra(s_tail, p, t, r_tail)
|
var *vars[4] = {vs, vp, vt, vr};
|
||||||
expr_ref s_tail(m_sk.mk_prefix_inv(vp, vs), m);
|
// base case: empty s or empty p -> r = s (no replacements)
|
||||||
expr_ref r_tail(m_sk.mk_prefix_inv(vt, vr), m);
|
expr_ref test1(m.mk_or(seq.str.mk_is_empty(vs), seq.str.mk_is_empty(vp)), m);
|
||||||
expr* args_match[4] = { s_tail, vp, vt, r_tail };
|
expr_ref branch1(m.mk_eq(vr, vs), m);
|
||||||
expr_ref test2(seq.str.mk_prefix(vp, vs), m);
|
// match case: prefix(p, s) -> s = p ++ s_tail, r = t ++ r_tail, ra(s_tail, p, t, r_tail)
|
||||||
expr_ref branch2(m.mk_and(m.mk_eq(vs, seq.str.mk_concat(vp, s_tail)),
|
expr_ref s_tail(m_sk.mk_prefix_inv(vp, vs), m);
|
||||||
m.mk_eq(vr, seq.str.mk_concat(vt, r_tail)),
|
expr_ref r_tail(m_sk.mk_prefix_inv(vt, vr), m);
|
||||||
m.mk_app(ra, 4, args_match)), m);
|
expr *args_match[4] = {s_tail, vp, vt, r_tail};
|
||||||
// no-match case: copy first char, ra(s[1:], p, t, r[1:])
|
expr_ref test2(seq.str.mk_prefix(vp, vs), m);
|
||||||
expr_ref s_head(m), s_tail2(m);
|
expr_ref branch2(m.mk_and(m.mk_eq(vs, seq.str.mk_concat(vp, s_tail)),
|
||||||
m_sk.decompose(vs, s_head, s_tail2);
|
m.mk_eq(vr, seq.str.mk_concat(vt, r_tail)), m.mk_app(ra, 4, args_match)),
|
||||||
expr_ref r_tail2(m_sk.mk_tail(vr, a.mk_int(0)), m);
|
m);
|
||||||
expr* args_skip[4] = { s_tail2, vp, vt, r_tail2 };
|
// no-match case: copy first char, ra(s[1:], p, t, r[1:])
|
||||||
expr_ref branch3(m.mk_and(m.mk_eq(vr, seq.str.mk_concat(s_head, r_tail2)),
|
expr_ref s_head(m), s_tail2(m);
|
||||||
m.mk_app(ra, 4, args_skip)), m);
|
m_sk.decompose(vs, s_head, s_tail2);
|
||||||
expr_ref body(m.mk_ite(test1, branch1, m.mk_ite(test2, branch2, branch3)), m);
|
expr_ref r_tail2(m_sk.mk_tail(vr, a.mk_int(0)), m);
|
||||||
plugin.set_definition(replace, d, false, 4, vars, body);
|
expr *args_skip[4] = {s_tail2, vp, vt, r_tail2};
|
||||||
|
expr_ref branch3(m.mk_and(m.mk_eq(vr, seq.str.mk_concat(s_head, r_tail2)), m.mk_app(ra, 4, args_skip)), m);
|
||||||
|
expr_ref body(m.mk_ite(test1, branch1, m.mk_ite(test2, branch2, branch3)), m);
|
||||||
|
TRACE(seq, tout << body << "\n");
|
||||||
|
plugin.set_definition(replace, d, false, 4, vars, body);
|
||||||
|
}
|
||||||
expr* args[4] = { s, p, t, r };
|
expr* args[4] = { s, p, t, r };
|
||||||
expr_ref lit(m.mk_app(ra, 4, args), m);
|
expr_ref lit(m.mk_app(ra, 4, args), m);
|
||||||
add_clause(lit);
|
add_clause(lit);
|
||||||
|
|
@ -1358,14 +1361,17 @@ namespace seq {
|
||||||
auto ca = purify(_a);
|
auto ca = purify(_a);
|
||||||
auto cb = purify(_b);
|
auto cb = purify(_b);
|
||||||
sort* srt = ca->get_sort();
|
sort* srt = ca->get_sort();
|
||||||
|
recfun::util rec(m);
|
||||||
|
sort *domain[2] = {srt, srt};
|
||||||
|
func_decl *not_contains = rec.find_def_decl(symbol("nc"), 2, domain, m.mk_bool_sort(), true);
|
||||||
|
|
||||||
|
if (!not_contains) {
|
||||||
|
|
||||||
if (!m_not_contains || m_not_contains->get_domain(0) != srt) {
|
|
||||||
recfun::util rec(m);
|
|
||||||
recfun::decl::plugin& plugin = rec.get_plugin();
|
recfun::decl::plugin& plugin = rec.get_plugin();
|
||||||
recfun_replace rf(m);
|
recfun_replace rf(m);
|
||||||
sort* domain[2] = { srt, srt };
|
|
||||||
auto d = plugin.ensure_def(symbol("nc"), 2, domain, m.mk_bool_sort(), true);
|
auto d = plugin.ensure_def(symbol("nc"), 2, domain, m.mk_bool_sort(), true);
|
||||||
m_not_contains = d.get_def()->get_decl();
|
not_contains = d.get_def()->get_decl();
|
||||||
var_ref vs(m.mk_var(1, srt), m);
|
var_ref vs(m.mk_var(1, srt), m);
|
||||||
var_ref vp(m.mk_var(0, srt), m);
|
var_ref vp(m.mk_var(0, srt), m);
|
||||||
expr_ref len_s(seq.str.mk_length(vs), m);
|
expr_ref len_s(seq.str.mk_length(vs), m);
|
||||||
|
|
@ -1376,7 +1382,7 @@ namespace seq {
|
||||||
expr_ref pref(seq.str.mk_prefix(vp, vs), m);
|
expr_ref pref(seq.str.mk_prefix(vp, vs), m);
|
||||||
expr_ref hd(seq.str.mk_unit(seq.str.mk_nth_i(vs, a.mk_int(0))), m);
|
expr_ref hd(seq.str.mk_unit(seq.str.mk_nth_i(vs, a.mk_int(0))), m);
|
||||||
expr_ref decomp(m.mk_eq(vs, seq.str.mk_concat(hd, tail)), m);
|
expr_ref decomp(m.mk_eq(vs, seq.str.mk_concat(hd, tail)), m);
|
||||||
expr_ref else_branch(m.mk_and(m.mk_not(pref), m.mk_and(decomp, m.mk_app(m_not_contains.get(), 2, nc_args))), m);
|
expr_ref else_branch(m.mk_and(m.mk_not(pref), m.mk_and(decomp, m.mk_app(not_contains, 2, nc_args))), m);
|
||||||
expr_ref body(m.mk_ite(a.mk_gt(len_p, len_s),
|
expr_ref body(m.mk_ite(a.mk_gt(len_p, len_s),
|
||||||
m.mk_true(),
|
m.mk_true(),
|
||||||
m.mk_ite(m.mk_eq(len_p, len_s),
|
m.mk_ite(m.mk_eq(len_p, len_s),
|
||||||
|
|
@ -1388,7 +1394,7 @@ namespace seq {
|
||||||
}
|
}
|
||||||
|
|
||||||
expr* app_args[2] = { ca.get(), cb.get() };
|
expr* app_args[2] = { ca.get(), cb.get() };
|
||||||
expr_ref nc_app(m.mk_app(m_not_contains.get(), 2, app_args), m);
|
expr_ref nc_app(m.mk_app(not_contains, 2, app_args), m);
|
||||||
expr_ref cnt(e, m);
|
expr_ref cnt(e, m);
|
||||||
add_clause(cnt, nc_app);
|
add_clause(cnt, nc_app);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ namespace seq {
|
||||||
arith_util a;
|
arith_util a;
|
||||||
seq_util seq;
|
seq_util seq;
|
||||||
skolem m_sk;
|
skolem m_sk;
|
||||||
func_decl_ref m_not_contains;
|
|
||||||
expr_ref_vector m_clause;
|
expr_ref_vector m_clause;
|
||||||
expr_ref_vector m_trail;
|
expr_ref_vector m_trail;
|
||||||
obj_map<expr, expr*> m_purified;
|
obj_map<expr, expr*> m_purified;
|
||||||
|
|
|
||||||
|
|
@ -150,6 +150,7 @@ namespace smt {
|
||||||
}
|
}
|
||||||
|
|
||||||
void theory_recfun::push(propagation_item* p) {
|
void theory_recfun::push(propagation_item* p) {
|
||||||
|
TRACE(recfun, tout << "push " << p << "\n");
|
||||||
m_propagation_queue.push_back(p);
|
m_propagation_queue.push_back(p);
|
||||||
ctx.push_trail(push_back_vector<scoped_ptr_vector<propagation_item>>(m_propagation_queue));
|
ctx.push_trail(push_back_vector<scoped_ptr_vector<propagation_item>>(m_propagation_queue));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue