mirror of
https://github.com/Z3Prover/z3
synced 2026-08-08 06:52:26 +00:00
Merge remote-tracking branch 'origin/master' into seq-dnf-opt
# Conflicts: # src/ast/rewriter/seq_monadic.cpp Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 57b9b87e-950a-49ea-bbb3-ed585646a5a9
This commit is contained in:
commit
8b92513413
8 changed files with 361 additions and 108 deletions
75
.github/workflows/build-warning-fixer.lock.yml
generated
vendored
75
.github/workflows/build-warning-fixer.lock.yml
generated
vendored
File diff suppressed because one or more lines are too long
63
.github/workflows/build-warning-fixer.md
vendored
63
.github/workflows/build-warning-fixer.md
vendored
|
|
@ -29,6 +29,7 @@ safe-outputs:
|
|||
network: defaults
|
||||
tools:
|
||||
github:
|
||||
mode: gh-proxy
|
||||
toolsets: [default, actions]
|
||||
bash: [":*"]
|
||||
timeout-minutes: 90
|
||||
|
|
@ -44,7 +45,7 @@ steps:
|
|||
|
||||
# Clang-Tidy Warning Fixer
|
||||
|
||||
You are an AI agent that uses clang-tidy warning output captured in GitHub Actions logs, proposes conservative fixes, and creates a GitHub issue with ready-to-apply git diffs.
|
||||
You are an AI agent that uses clang-tidy warning output captured in a GitHub Actions artifact, proposes conservative fixes, and creates a GitHub issue with ready-to-apply git diffs.
|
||||
|
||||
## Current Context
|
||||
|
||||
|
|
@ -63,58 +64,36 @@ This workflow is only for `Z3Prover/z3`.
|
|||
|
||||
If `${{ github.repository }}` is not `Z3Prover/z3`, call `noop` immediately with a short explanation.
|
||||
|
||||
### 1. Retrieve logs from `clang-tidy-warning-report.yml`
|
||||
### 1. Retrieve the artifact from `clang-tidy-warning-report.yml`
|
||||
|
||||
Use GitHub MCP tools (not `gh`) to retrieve job logs from the triggering run. Do not use `download_workflow_run_artifact`: it may be unavailable, and this workflow must operate entirely from Actions logs.
|
||||
Use the authenticated `gh` CLI proxy to retrieve the warning artifact from the triggering run.
|
||||
|
||||
1. Determine source run ID:
|
||||
- If `${{ github.event.workflow_run.id }}` is present, use it.
|
||||
- For manual dispatch, call `github-mcp-server-actions_list` (`list_workflow_runs`) for workflow `clang-tidy-warning-report.yml` and select the latest `completed` run.
|
||||
2. List jobs for that run with `github-mcp-server-actions_list` (`list_workflow_jobs`).
|
||||
3. Identify the job named `Build Z3 with clang-tidy warnings`.
|
||||
4. Retrieve its logs with `github-mcp-server-get_job_logs` using `return_content: true` and a large `tail_lines` value so the appended summary block is included.
|
||||
5. Save the returned log content locally for repeatable analysis:
|
||||
- For manual dispatch, use `gh run list` for workflow `clang-tidy-warning-report.yml` and select the latest completed run.
|
||||
2. Download and extract the artifact:
|
||||
|
||||
```bash
|
||||
RUN_ID="${{ github.event.workflow_run.id }}"
|
||||
if [ -z "$RUN_ID" ]; then
|
||||
RUN_ID="$(gh run list --repo "${{ github.repository }}" \
|
||||
--workflow clang-tidy-warning-report.yml --status completed --limit 1 \
|
||||
--json databaseId --jq '.[0].databaseId')"
|
||||
fi
|
||||
|
||||
rm -rf /tmp/gh-aw/clang-tidy-warning-report
|
||||
mkdir -p /tmp/gh-aw/clang-tidy-warning-report
|
||||
cat <<'EOF' > /tmp/gh-aw/clang-tidy-warning-report/build.log
|
||||
$JOB_LOG_CONTENT
|
||||
EOF
|
||||
cp /tmp/gh-aw/clang-tidy-warning-report/build.log /tmp/gh-aw/clang-tidy-warning-report/combined.log
|
||||
gh run download "$RUN_ID" --repo "${{ github.repository }}" \
|
||||
--name "clang-tidy-warning-report-$RUN_ID" \
|
||||
--dir /tmp/gh-aw/clang-tidy-warning-report
|
||||
ls -la /tmp/gh-aw/clang-tidy-warning-report
|
||||
```
|
||||
|
||||
The source workflow emits a marker-delimited summary near the end of the job log:
|
||||
|
||||
- `CLANG_TIDY_WARNING_REPORT_BEGIN`
|
||||
- `CLANG_TIDY_STATUS_BEGIN` / `CLANG_TIDY_STATUS_END`
|
||||
- `CLANG_TIDY_WARNINGS_BEGIN` / `CLANG_TIDY_WARNINGS_END`
|
||||
- `CLANG_TIDY_WARNING_REPORT_END`
|
||||
|
||||
Extract the summary into local files:
|
||||
|
||||
```bash
|
||||
sed -n '/^CLANG_TIDY_STATUS_BEGIN$/,/^CLANG_TIDY_STATUS_END$/p' \
|
||||
/tmp/gh-aw/clang-tidy-warning-report/combined.log | sed '1d;$d' \
|
||||
> /tmp/gh-aw/clang-tidy-warning-report/status.txt
|
||||
|
||||
sed -n '/^CLANG_TIDY_WARNINGS_BEGIN$/,/^CLANG_TIDY_WARNINGS_END$/p' \
|
||||
/tmp/gh-aw/clang-tidy-warning-report/combined.log | sed '1d;$d' \
|
||||
> /tmp/gh-aw/clang-tidy-warning-report/warnings.txt
|
||||
```
|
||||
|
||||
If the marker block is missing, fall back to grepping the full log:
|
||||
|
||||
```bash
|
||||
grep -nE 'warning:|error:|clang-tidy' /tmp/gh-aw/clang-tidy-warning-report/combined.log \
|
||||
> /tmp/gh-aw/clang-tidy-warning-report/warnings.txt || true
|
||||
```
|
||||
|
||||
Expect at minimum `build.log`, `combined.log`, and `warnings.txt`. Prefer using `status.txt` when extracted successfully. If the job log is unavailable or empty, call `noop` with a concise explanation.
|
||||
Expect `configure.log`, `build.log`, `combined.log`, `warnings.txt`, and `status.txt`. If the artifact is unavailable, expired, or empty, call `noop` with a concise explanation.
|
||||
|
||||
### 2. Extract actionable diagnostics
|
||||
|
||||
Analyze log-derived files from this run:
|
||||
Analyze artifact files from this run:
|
||||
- `/tmp/gh-aw/clang-tidy-warning-report/warnings.txt`
|
||||
- `/tmp/gh-aw/clang-tidy-warning-report/build.log`
|
||||
- `/tmp/gh-aw/clang-tidy-warning-report/combined.log`
|
||||
|
|
@ -196,7 +175,7 @@ Issue content must include:
|
|||
- proposed fixes as unified diffs (full diff text, not prose only)
|
||||
- short assignment-ready checklist for Copilot (one checkbox per proposed fix)
|
||||
|
||||
If no actionable warnings are found, or the source job logs are missing/corrupt, call `noop` with a concise explanation.
|
||||
If no actionable warnings are found, or the source artifact is missing/corrupt, call `noop` with a concise explanation.
|
||||
|
||||
## Guidelines
|
||||
|
||||
|
|
@ -204,4 +183,4 @@ If no actionable warnings are found, or the source job logs are missing/corrupt,
|
|||
- Prefer no issue over risky or speculative patch suggestions.
|
||||
- Keep fixes surgical and easy to review.
|
||||
- Focus only on diagnostics produced by the referenced `clang-tidy-warning-report.yml` run.
|
||||
- Prefer workflow job logs over cross-run artifact downloads, even if artifact metadata is visible.
|
||||
- Use only the warning artifact from the selected workflow run.
|
||||
|
|
|
|||
|
|
@ -59,6 +59,36 @@ Author:
|
|||
#include <algorithm>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace {
|
||||
char const* mode_name(seq::transition_mode mode) {
|
||||
switch (mode) {
|
||||
case seq::transition_mode::brzozowski_tm:
|
||||
return "brzozowski";
|
||||
case seq::transition_mode::light_antimirov_tm:
|
||||
return "light-antimirov";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
char const* bail_name(unsigned i) {
|
||||
static char const* const names[] = {
|
||||
"unsupported",
|
||||
"state-cap",
|
||||
"dnf-cap",
|
||||
"budget",
|
||||
"resource",
|
||||
"nullability",
|
||||
"guard"
|
||||
};
|
||||
return i < std::size(names) ? names[i] : "unknown";
|
||||
}
|
||||
|
||||
char const* result_name(lbool r) {
|
||||
return r == l_true ? "sat" : r == l_false ? "unsat" : "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
expr_ref seq_monadic::der_elem(expr* r, expr* elem) {
|
||||
expr* cached = nullptr;
|
||||
|
|
@ -375,6 +405,8 @@ unsigned seq_monadic::var_index(expr* v) {
|
|||
}
|
||||
|
||||
void seq_monadic::reset_search() {
|
||||
m_seq_sort = nullptr;
|
||||
m_elem_sort = nullptr;
|
||||
m_atoms.reset();
|
||||
m_regexes.reset();
|
||||
m_vars.reset();
|
||||
|
|
@ -799,39 +831,43 @@ lbool seq_monadic::choose_cont(unsigned vi, svector<unsigned> const& S, unsigned
|
|||
}
|
||||
|
||||
lbool seq_monadic::decide(membership_vec const& memberships) {
|
||||
m_last_search_memberships = memberships;
|
||||
m_model.reset();
|
||||
if (memberships.empty())
|
||||
return l_true; // empty conjunction is vacuously true
|
||||
reset_search(); // clear the caches before dropping the
|
||||
m_pin.reset(); // pins that keep their keys alive
|
||||
m_rp_cache.maybe_reset(1u << 16);
|
||||
m_rw.get_derive().maybe_reset_cached_cofactors(1u << 16);
|
||||
m_budget = 200000;
|
||||
m_giveup = false;
|
||||
if (!prepare(memberships))
|
||||
return l_undef;
|
||||
lbool r;
|
||||
if (m_config.m_state_search) {
|
||||
// Build one cursor per membership at its regex start; initial_normalize consumes
|
||||
// leading constants so every active cursor exposes a variable head.
|
||||
m_cursors.reset();
|
||||
for (unsigned mi = 0; mi < m_atoms.size(); ++mi)
|
||||
m_cursors.push_back(cursor{ 0, m_regexes.get(mi), false });
|
||||
m_last_var = UINT_MAX;
|
||||
lbool norm = initial_normalize();
|
||||
r = (norm == l_false) ? l_false : search();
|
||||
lbool r = l_true; // empty conjunction is vacuously true
|
||||
if (!memberships.empty() && !prepare(memberships))
|
||||
r = l_undef;
|
||||
else if (!memberships.empty()) {
|
||||
if (m_config.m_state_search) {
|
||||
// Build one cursor per membership at its regex start; initial_normalize consumes
|
||||
// leading constants so every active cursor exposes a variable head.
|
||||
m_cursors.reset();
|
||||
for (unsigned mi = 0; mi < m_atoms.size(); ++mi)
|
||||
m_cursors.push_back(cursor{ 0, m_regexes.get(mi), false });
|
||||
m_last_var = UINT_MAX;
|
||||
lbool norm = initial_normalize();
|
||||
r = (norm == l_false) ? l_false : search();
|
||||
}
|
||||
else
|
||||
r = dfs_membership(0);
|
||||
}
|
||||
else
|
||||
r = dfs_membership(0);
|
||||
if (r != l_true)
|
||||
m_model.reset();
|
||||
m_last_search_result = r;
|
||||
return r;
|
||||
}
|
||||
|
||||
lbool seq_monadic::solve(expr* term, expr* R) {
|
||||
m_core.reset();
|
||||
membership_vec mv;
|
||||
mv.push_back({ expr_ref(term, m), expr_ref(R, m), nullptr });
|
||||
return decide(mv);
|
||||
m_last_result = decide(mv);
|
||||
return m_last_result;
|
||||
}
|
||||
|
||||
void seq_monadic::add(expr* term, expr* regex, void* d) {
|
||||
|
|
@ -930,9 +966,132 @@ void seq_monadic::minimize_core(membership_vec const& memberships) {
|
|||
lbool seq_monadic::check() {
|
||||
m_core.reset();
|
||||
lbool r = decide(m_memberships);
|
||||
if (r == l_false)
|
||||
if (r == l_false) {
|
||||
minimize_core(m_memberships);
|
||||
return r;
|
||||
m_model.reset();
|
||||
}
|
||||
m_last_result = r;
|
||||
return m_last_result;
|
||||
}
|
||||
|
||||
std::ostream& seq_monadic::display(std::ostream& out) const {
|
||||
auto display_expr = [&](expr* e) {
|
||||
if (e)
|
||||
out << mk_pp(e, m);
|
||||
else
|
||||
out << "null";
|
||||
};
|
||||
|
||||
out << "(seq-monadic\n"
|
||||
<< " :mode " << mode_name(m_config.m_mode) << "\n"
|
||||
<< " :generate-model " << (m_config.m_model ? "true" : "false") << "\n"
|
||||
<< " :minimize-core " << (m_config.m_min_core ? "true" : "false") << "\n"
|
||||
<< " :last-result " << result_name(m_last_result) << "\n"
|
||||
<< " :budget " << m_budget << "\n"
|
||||
<< " :giveup " << (m_giveup ? "true" : "false") << "\n"
|
||||
<< " :sequence-sort ";
|
||||
if (m_seq_sort)
|
||||
out << mk_pp(m_seq_sort, m);
|
||||
else
|
||||
out << "null";
|
||||
out << "\n :element-sort ";
|
||||
if (m_elem_sort)
|
||||
out << mk_pp(m_elem_sort, m);
|
||||
else
|
||||
out << "null";
|
||||
|
||||
out << "\n :memberships (";
|
||||
for (unsigned i = 0; i < m_memberships.size(); ++i) {
|
||||
auto const& [term, regex, dep] = m_memberships[i];
|
||||
out << "\n [" << i << "] ";
|
||||
display_expr(term);
|
||||
out << " in ";
|
||||
display_expr(regex);
|
||||
out << " :dependency " << dep;
|
||||
}
|
||||
if (!m_memberships.empty())
|
||||
out << "\n ";
|
||||
out << ")\n :model (";
|
||||
for (auto const& [var, value] : m_model) {
|
||||
out << "\n ";
|
||||
display_expr(var);
|
||||
out << " -> ";
|
||||
display_expr(value);
|
||||
}
|
||||
if (!m_model.empty())
|
||||
out << "\n ";
|
||||
out << ")\n :core (";
|
||||
for (void* dep : m_core)
|
||||
out << " " << dep;
|
||||
out << " )";
|
||||
|
||||
out << "\n :last-internal-search\n"
|
||||
<< " (:result " << result_name(m_last_search_result)
|
||||
<< "\n :memberships (";
|
||||
for (unsigned i = 0; i < m_last_search_memberships.size(); ++i) {
|
||||
auto const& [term, regex, dep] = m_last_search_memberships[i];
|
||||
out << "\n [" << i << "] ";
|
||||
display_expr(term);
|
||||
out << " in ";
|
||||
display_expr(regex);
|
||||
out << " :dependency " << dep;
|
||||
}
|
||||
if (!m_last_search_memberships.empty())
|
||||
out << "\n ";
|
||||
out << ")\n :variables (";
|
||||
for (expr* var : m_vars) {
|
||||
out << " ";
|
||||
display_expr(var);
|
||||
}
|
||||
out << " )\n :parsed-memberships (";
|
||||
for (unsigned mi = 0; mi < m_atoms.size(); ++mi) {
|
||||
out << "\n [" << mi << "] :regex ";
|
||||
display_expr(m_regexes.get(mi));
|
||||
out << " :atoms (";
|
||||
for (atom const& a : m_atoms[mi]) {
|
||||
out << " " << (a.is_var ? "var:" : "elem:");
|
||||
display_expr(a.is_var ? a.var.get() : a.elem.get());
|
||||
}
|
||||
out << " )";
|
||||
}
|
||||
if (!m_atoms.empty())
|
||||
out << "\n ";
|
||||
out << ")\n :groups (";
|
||||
for (unsigned vi = 0; vi < m_groups.size(); ++vi) {
|
||||
out << "\n ";
|
||||
display_expr(m_vars[vi]);
|
||||
out << " (";
|
||||
for (component const& c : m_groups[vi]) {
|
||||
out << "\n ";
|
||||
display_expr(c.state);
|
||||
if (c.target) {
|
||||
out << " -> ";
|
||||
display_expr(c.target);
|
||||
}
|
||||
else {
|
||||
out << " nullable";
|
||||
}
|
||||
}
|
||||
if (!m_groups[vi].empty())
|
||||
out << "\n ";
|
||||
out << ")";
|
||||
}
|
||||
if (!m_groups.empty())
|
||||
out << "\n ";
|
||||
out << ")\n"
|
||||
<< " :undefined-variables " << m_undef_vars << "\n"
|
||||
<< " :group-cache-size " << m_group_cache.size() << "\n"
|
||||
<< " :derivative-cache-size " << m_der_cache.size() << "\n"
|
||||
<< " :nullable-cache-size " << m_nullable_cache.size() << "\n"
|
||||
<< " :live-cache-size " << m_live_cache.size() << "\n"
|
||||
<< " :pinned-expressions " << m_pin.size() << ")\n";
|
||||
|
||||
out << " :statistics\n"
|
||||
<< " (:cofactor-calls " << m_stats.m_cofactor_calls << "\n"
|
||||
<< " :states " << m_stats.m_states;
|
||||
for (unsigned i = 0; i < static_cast<unsigned>(bail_reason::num_reasons); ++i)
|
||||
out << "\n :bail-" << bail_name(i) << " " << m_stats.m_bails[i];
|
||||
return out << "))\n";
|
||||
}
|
||||
|
||||
void seq_monadic::collect_statistics(::statistics& st) const {
|
||||
|
|
|
|||
|
|
@ -121,8 +121,11 @@ class seq_monadic {
|
|||
// seq_rewriter's own cache is capped and flushed whole
|
||||
using membership_vec = vector<std::tuple<expr_ref, expr_ref, void*>>;
|
||||
membership_vec m_memberships; // asserted (term in regex, dep) for check()
|
||||
membership_vec m_last_search_memberships; // inputs used by the last internal decide()
|
||||
ptr_vector<void> m_core; // dependencies of an unsat subset, filled by check() on l_false
|
||||
std::function<bool(expr *)> m_is_var; // predicate for whether a term is a sequence variable
|
||||
lbool m_last_result = l_undef; // result of the last public solve()/check()
|
||||
lbool m_last_search_result = l_undef; // result of the last internal decide()
|
||||
|
||||
seq_util& u() const { return m_rw.u(); }
|
||||
seq_util::rex& re() const { return m_rw.u().re; }
|
||||
|
|
@ -295,6 +298,9 @@ public:
|
|||
|
||||
void collect_statistics(::statistics &st) const;
|
||||
|
||||
// Display asserted constraints, result artifacts, search state, caches, and counters.
|
||||
std::ostream& display(std::ostream& out) const;
|
||||
|
||||
seq::transition_mode mode() const { return m_config.m_mode; }
|
||||
|
||||
// Enable/disable model generation (default: enabled). When enabled, a successful
|
||||
|
|
|
|||
|
|
@ -373,6 +373,19 @@ bool cmd_context::contains_func_decl(symbol const& s, unsigned n, sort* const* d
|
|||
return m_func_decls.find(s, fs) && fs.contains(n, domain, range);
|
||||
}
|
||||
|
||||
bool cmd_context::builtin_signature_collides(symbol const& s, unsigned arity, sort* const* domain) const {
|
||||
expr_ref_vector args(m());
|
||||
for (unsigned i = 0; i < arity; ++i)
|
||||
args.push_back(m().mk_var(i, domain[i]));
|
||||
expr_ref result(m());
|
||||
try {
|
||||
return try_mk_builtin_app(s, arity, args.data(), 0, nullptr, nullptr, result);
|
||||
}
|
||||
catch (ast_exception&) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool cmd_context::contains_macro(symbol const& s) const {
|
||||
macro_decls decls;
|
||||
return m_macros.find(s, decls) && !decls.empty();
|
||||
|
|
@ -938,11 +951,12 @@ void cmd_context::insert(symbol const & s, func_decl * f) {
|
|||
if (contains_macro(s, f)) {
|
||||
throw cmd_exception("invalid declaration, named expression already defined with this name ", s);
|
||||
}
|
||||
#if 0
|
||||
if (m_builtin_decls.contains(s)) {
|
||||
throw cmd_exception("invalid declaration, builtin symbol ", s);
|
||||
if (builtin_signature_collides(s, f->get_arity(), f->get_domain())) {
|
||||
std::string msg = "invalid declaration, builtin symbol '";
|
||||
msg += s.str();
|
||||
msg += "' has the same argument sorts";
|
||||
throw cmd_exception(std::move(msg));
|
||||
}
|
||||
#endif
|
||||
func_decls & fs = m_func_decls.insert_if_not_there(s, func_decls());
|
||||
if (!fs.insert(m(), f)) {
|
||||
if (m_allow_duplicate_declarations)
|
||||
|
|
@ -980,11 +994,12 @@ void cmd_context::insert(symbol const & s, psort_decl * p) {
|
|||
|
||||
void cmd_context::insert(symbol const & s, unsigned arity, sort *const* domain, expr * t) {
|
||||
expr_ref _t(t, m());
|
||||
#if 0
|
||||
if (m_builtin_decls.contains(s)) {
|
||||
throw cmd_exception("invalid macro/named expression, builtin symbol ", s);
|
||||
if (builtin_signature_collides(s, arity, domain)) {
|
||||
std::string msg = "invalid named expression, builtin symbol '";
|
||||
msg += s.str();
|
||||
msg += "' has the same argument sorts";
|
||||
throw cmd_exception(std::move(msg));
|
||||
}
|
||||
#endif
|
||||
if (contains_macro(s, arity, domain)) {
|
||||
throw cmd_exception("named expression already defined");
|
||||
}
|
||||
|
|
@ -2570,4 +2585,3 @@ std::ostream & operator<<(std::ostream & out, cmd_context::status st) {
|
|||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -364,6 +364,7 @@ protected:
|
|||
void mk_solver();
|
||||
|
||||
bool contains_func_decl(symbol const& s, unsigned n, sort* const* domain, sort* range) const;
|
||||
bool builtin_signature_collides(symbol const& s, unsigned arity, sort* const* domain) const;
|
||||
|
||||
bool contains_macro(symbol const& s) const;
|
||||
bool contains_macro(symbol const& s, func_decl* f) const;
|
||||
|
|
@ -581,4 +582,3 @@ public:
|
|||
|
||||
std::ostream & operator<<(std::ostream & out, cmd_context::status st);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ Author:
|
|||
#include "params/smt_params.h"
|
||||
#include "smt/smt_kernel.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
|
||||
namespace {
|
||||
|
|
@ -467,6 +468,68 @@ public:
|
|||
std::cout << (trail_ok ? " OK " : " FAIL ")
|
||||
<< "check preserves assertions and pop removes them\n";
|
||||
|
||||
std::cout << "=== seq_monadic: display ===\n";
|
||||
m_trail.push_scope();
|
||||
unsigned display_dep = 0;
|
||||
m_mon.set_gen_model(true);
|
||||
m_mon.add(x, aaS, &display_dep);
|
||||
lbool display_result = m_mon.check();
|
||||
std::ostringstream display_out;
|
||||
m_mon.display(display_out);
|
||||
std::string display_text = display_out.str();
|
||||
bool display_ok =
|
||||
display_result == l_true &&
|
||||
display_text.find("(seq-monadic") != std::string::npos &&
|
||||
display_text.find(":memberships") != std::string::npos &&
|
||||
display_text.find(":model") != std::string::npos &&
|
||||
display_text.find(":last-result sat") != std::string::npos &&
|
||||
display_text.find(":last-internal-search") != std::string::npos &&
|
||||
display_text.find(":parsed-memberships") != std::string::npos &&
|
||||
display_text.find(":statistics") != std::string::npos &&
|
||||
display_text.find("x") != std::string::npos;
|
||||
m_trail.pop_scope(1);
|
||||
if (!display_ok) ++m_fail;
|
||||
std::cout << (display_ok ? " OK " : " FAIL ")
|
||||
<< "display exposes readable solver state\n";
|
||||
|
||||
m_trail.push_scope();
|
||||
unsigned display_dep1 = 1, display_dep2 = 2;
|
||||
m_mon.set_min_core(true);
|
||||
m_mon.add(x, aaS, &display_dep1);
|
||||
m_mon.add(x, a_aaS, &display_dep2);
|
||||
lbool unsat_display_result = m_mon.check();
|
||||
std::ostringstream unsat_display_out;
|
||||
m_mon.display(unsat_display_out);
|
||||
std::string unsat_display_text = unsat_display_out.str();
|
||||
bool unsat_display_ok =
|
||||
unsat_display_result == l_false &&
|
||||
unsat_display_text.find(":last-result unsat") != std::string::npos &&
|
||||
unsat_display_text.find(":model ()") != std::string::npos &&
|
||||
unsat_display_text.find(":last-internal-search") != std::string::npos;
|
||||
m_trail.pop_scope(1);
|
||||
m_mon.set_min_core(false);
|
||||
if (!unsat_display_ok) ++m_fail;
|
||||
std::cout << (unsat_display_ok ? " OK " : " FAIL ")
|
||||
<< "display distinguishes unsat result from core-search state\n";
|
||||
|
||||
lbool solve_display_result = m_mon.solve(x, aaS);
|
||||
std::ostringstream solve_display_out;
|
||||
m_mon.display(solve_display_out);
|
||||
bool solve_display_ok =
|
||||
solve_display_result == l_true &&
|
||||
solve_display_out.str().find(":core ( )") != std::string::npos;
|
||||
lbool empty_display_result = m_mon.check();
|
||||
std::ostringstream empty_display_out;
|
||||
m_mon.display(empty_display_out);
|
||||
std::string empty_display_text = empty_display_out.str();
|
||||
bool empty_display_ok =
|
||||
empty_display_result == l_true &&
|
||||
empty_display_text.find(":sequence-sort null") != std::string::npos &&
|
||||
empty_display_text.find(":element-sort null") != std::string::npos;
|
||||
if (!solve_display_ok || !empty_display_ok) ++m_fail;
|
||||
std::cout << (solve_display_ok && empty_display_ok ? " OK " : " FAIL ")
|
||||
<< "display clears artifacts across solve and empty check\n";
|
||||
|
||||
std::cout << "=== seq_monadic: length bounds ===\n";
|
||||
auto check_bound = [&](char const* name, expr* regex, unsigned bound, bool is_lo,
|
||||
lbool expected) {
|
||||
|
|
|
|||
|
|
@ -257,6 +257,36 @@ void test_symbol_escape() {
|
|||
std::cout << "done evaluating\n";
|
||||
}
|
||||
|
||||
void test_builtin_signature_clash() {
|
||||
char const* rejected[] = {
|
||||
"(declare-fun and (Bool Bool) Int)",
|
||||
"(define-fun not ((a Bool)) Bool false)",
|
||||
"(declare-const true Bool)",
|
||||
"(define-fun = ((a Int) (b Int)) Bool true)",
|
||||
"(define-fun ite ((c Bool) (a Int) (b Int)) Int 0)",
|
||||
"(define-fun + ((a Int) (b Int)) Int 0)",
|
||||
"(define-fun-rec and ((a Bool) (b Bool)) Bool false)"
|
||||
};
|
||||
|
||||
for (char const* spec : rejected) {
|
||||
Z3_context ctx = Z3_mk_context(nullptr);
|
||||
Z3_set_error_handler(ctx, setError);
|
||||
is_error = false;
|
||||
Z3_parse_smtlib2_string(ctx, spec, 0, nullptr, nullptr, 0, nullptr, nullptr);
|
||||
ENSURE(is_error);
|
||||
Z3_del_context(ctx);
|
||||
}
|
||||
|
||||
Z3_context ctx = Z3_mk_context(nullptr);
|
||||
Z3_set_error_handler(ctx, setError);
|
||||
test_eval(ctx,
|
||||
"(declare-fun and (Int Int) Int)\n"
|
||||
"(assert (= (and 1 2) 0))\n"
|
||||
"(check-sat)\n",
|
||||
false);
|
||||
Z3_del_context(ctx);
|
||||
}
|
||||
|
||||
void tst_smt2print_parse() {
|
||||
|
||||
// test basic datatypes
|
||||
|
|
@ -326,6 +356,7 @@ void tst_smt2print_parse() {
|
|||
test_ho_choice_expression();
|
||||
|
||||
test_symbol_escape();
|
||||
test_builtin_signature_clash();
|
||||
|
||||
// Regression test for GitHub issue #10166:
|
||||
// With (set-option :smtlib2_compliant true), a formula involving to_real
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue