Use the singleton value in place of a singleton-sorted variable - #219
Merged
Conversation
coord-e
force-pushed
the
claude/issue-217-n8w210
branch
from
August 14, 2026 06:57
ffe6e09 to
d7a0530
Compare
`Env::dependencies` withholds a clause variable from a local whose sort is singleton, but `Env::var_type` still referred to such a local by name. Storing the local into an aggregate that also has a non-singleton field carried that name into the aggregate's term, and the aggregate does get a clause variable, so the reference reached clause construction and aborted there: `unbound var` in `ClauseBuilder::mapped_var` when the aggregate's `fn` field is called, or a missing substitution in `PrecondCapture::finish` when the aggregate is merely held across a basic-block boundary. A singleton sort has exactly one value, so name the value itself instead. The two test pairs differ in whether the `fn` field is called, which is what selects between the two consumers. The type of the null-sorted field does not: a `&str` field reaches the same `PrecondCapture` abort as an uncalled `fn` one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MyiZkfhBzL1EAqmDMLLN6Q
coord-e
force-pushed
the
claude/issue-217-n8w210
branch
from
August 14, 2026 07:47
d7a0530 to
b76f7fa
Compare
coord-e
marked this pull request as ready for review
August 14, 2026 07:49
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes dangling references to singleton-sorted locals during CHC construction by substituting their canonical singleton value.
Changes:
- Use
Term::default_forfor singleton sorts inEnv::var_type. - Add paired UI tests covering successful and failing tuple verification.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
src/refine/env.rs |
Replaces unregistered singleton variables with canonical values. |
tests/ui/pass/fn_ptr_tuple_field.rs |
Verifies the valid function-pointer tuple case. |
tests/ui/fail/fn_ptr_tuple_field.rs |
Confirms an invalid assertion remains unsatisfiable. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #217.
Problem
Env::dependencieswithholds a clause variable from a local whose sort is singleton — such a value carries no logical content, and the rest of the codebase assumes the same (Template::build,with_value_var, andFrom<PlaceType> for RefinedTypeall skip singleton sorts the same way).Env::var_type, however, still referred to such a local by name. Storing the local into an aggregate that also has a non-singleton field carried that name into the aggregate's term, and the aggregate does get a clause variable — so the reference survived into clause construction and aborted there, at either of two consumers:ClauseBuilder::mapped_var—unbound var _2PrecondCapture::finish—no entry found for keyBoth
Type::FunctionandType::Stringlower tochc::Sort::Null, so afn(..)pointer and a&strreproduce it alike; it is the mixture of a null-sorted field with a non-singleton one that triggers it, not the function pointer, the call, or the aggregate kind.Fix
A singleton sort has exactly one value, so
var_typenames that value (chc::Term::default_for) instead of the variable. Nothing dangling reaches clause construction.Test
One pass/fail pair,
fn_ptr_tuple_field: a(fn(i64) -> i64, i64)tuple whosefnfield is called.This single program covers both panic sites. Verified on the base commit
cd33fbfby suppressing themapped_varpanic — the same program then aborts inPrecondCapture::finish, so the call path and the block-boundary path are both exercised. A no-call variant, and a&str-instead-of-fnvariant, were both tried and dropped: each reaches onlyPrecondCapture::finish, a strict subset, and neither can fail independently of this pair.Verification
Unsat, so the fix does not paper over the check.fmt,clippy, andtestall pass.tests/ui/fail/option_map.rscould not be run locally — it reportsverification error: Timeout(30s)identically at the base commitcd33fbfand on this branch, because its pcsat solver runs under Docker in the dev container and cannot find the counterexample within the 30s solver timeout. CI has more headroom and runs it green, confirming it is unrelated to this change.Out of scope
dependenciesfilters singleton locals but not singleton temps; temps are always registered, which is why that path never hit this asymmetry.Type::Neveralso lowers toSort::Nulland is presumably covered by the same change, but no case was constructed to confirm it.