Identify annotation quantified variables by a system-unique ID - #313
Conversation
`pre!`/`post!` substitute the call's arguments into the closure's annotation formula, and substitution goes under binders without renaming them. When an argument mentions an outer binder, such as the `i` in `Option::map`'s `exists(|i| opt == Some(i) && pre!(f(i)))`, and the closure's formula binds a variable of the same name, the inner binder captures it. A closure requiring `exists(|i: i64| x == i + i)` then accepted any argument, so `Some(3).map(half)` verified although the closure panics on it. Name each binder after its HirId so no two annotations share a binder. Fixes #312 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0188UiLozh1wCkmzZxJvzUTS
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
A variable bound by `forall`/`exists` in an annotation was identified by its source name alone, and `pre!`/`post!` put the closure's annotation formula under the caller annotation's quantifier. A variable of the caller's quantifier passed as an argument then met a quantifier of the closure's formula with the same name, and was bound by it. Replace `Term::FormulaQuantifiedVar(Sort, String)` with `Term::UserQuantifiedVar(Sort, UserQuantifiedVarId)`, where the ID is issued by the CHC system like `PredVarId`, so that variables of different quantifiers are never confused. Fixes #312 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0188UiLozh1wCkmzZxJvzUTS
|
I don't think this PR causes it. The test has no Generated by Claude Code |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0188UiLozh1wCkmzZxJvzUTS
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0188UiLozh1wCkmzZxJvzUTS
…antified variables take upstream's UserQuantifiedVarId The fork's laws (closure_unnest, trait laws in pred_inst) and the candidate atoms' skolem slots now use system-issued ids in place of name-keyed binders. Each id is issued with the source name or law variable it stands for; with logging on (RUST_LOG at info or below) the SMT-LIB2 output starts with a comment naming what each q$<n> stands for. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fixes #312.
A variable bound by
forall/existsin an annotation was represented asTerm::FormulaQuantifiedVar(Sort, String), tied to its quantifier by the source name alone.pre!(f(..))/post!(f(..), ..)build the closure's annotation formula with its parameters replaced by argument terms from the caller's annotation. When an argument contains the caller's quantified variable (such as theiinOption::map's specexists(|i| opt == Some(i) && pre!(f(i)))) and the closure's formula has a quantifier with the same name, the two can't be told apart, and the inner quantifier binds both. Here is an example:This verified as safe, although the closure panics on
3.Change
Term::FormulaQuantifiedVar(Sort, String)→Term::UserQuantifiedVar(Sort, UserQuantifiedVarId).Formula::Exists/ForallbindVec<(UserQuantifiedVarId, Sort)>.UserQuantifiedVarIdis issued bySystem::new_user_quantified_var, so it is unique in the CHC system likePredVarId. The annotation translator gets one per quantified variable throughAnalyzer::generate_user_quantified_var.q$<n>. Theq$prefix keeps these names apart from the generated clause variables, as in Keep spec quantifier binders from capturing clause variables #295.Testing
Unsat, andSome(4).map(half)verifies. No test is added for it.cargo test,cargo fmt --checkandcargo clippy -D warningspass locally.🤖 Generated with Claude Code
https://claude.ai/code/session_0188UiLozh1wCkmzZxJvzUTS