Repository navigation
fix: preserve negated Array.isArray ternary branches - #229
Merged
Merged
Conversation
There was a problem hiding this comment.
Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.
An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.
namin
approved these changes
Oct 27, 2026
Member
|
Thanks for your contributions! |
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.
Problem
A negated array-union test reverses the source branches during structural
narrowing. This changes the modeled return value, so Dafny can prove a
postcondition that is false of the original TypeScript.
Reproduction
Expected
Strings return
1; arrays return2. Negated array-union ternaries arealready documented in TOOLS.md's narrowing table.
Actual
On
ffc07fcf1e6826b57fad0dde6e8bc2bbfb960ab5, the generated match mapsNonArrayBranchto2and its fallthrough to1. A real Dafny run verifiesthe reversed claims (1 verified, 0 errors) and rejects the correct claims.
Root cause
Raw and Typed IR retain the correct conditional. In
ruleConditionalArrayIsArray, selectingNonArrayBranchalready accountsfor negation, but the rule also swaps the then/else expressions.
Fix
Keep the source then-branch in the selected variant and the source else-branch
in the fallthrough. Positive
Array.isArrayandtypeof ... === "string"tests retain their existing branch mapping.
Regression
Add bare-variable and field-path fixtures with correct contracts. The unit
tests execute the TypeScript boundary cases and inspect narrowed IR and both
emissions; all three fail before the fix and pass afterward. The standard
fixture script verifies both functions with real Dafny.
Validation
npm run build— pass.(cd tools && npm run typecheck)— pass.npm run typecheck:examples— pass.npx tsx --test tools/tests/*.test.ts— 292 passed on Linux/Node 24.bash tools/test-fixtures.sh— pass with Dafny 4.11.0.bash regen-lean.shandbash regen-dafny.sh --no-verify— pass, noexisting generated/proof drift.
lake build— pass with Lean 4.34.0 and Velvetlemma2.Generated minimal reproduction: both universal return-value theorems and
prove_correct choosepass in Lean.External
pi-lemmascriptat1ec4040cfcd7e20b3039b0abfa05660431aa8458:all six listed Dafny files pass (30 verified members), no artifact drift.
bash tools/check.sh dafny examples/*.ts— all 71 Dafny-enabled examplespass (469 reported verified members); one declared Lean-only example is
skipped. No generated or proof-file drift afterward. The source checkout
has no root manifest, so the example paths are passed explicitly.
The Windows baseline has 29 existing CLI-subprocess test failures related to
absolute ESM loader paths; the Linux baseline passes all 289 original tests.
Backend impact
Dafny: the correct claims now verify; the previously verified false claims
fail. Both regression functions verify (2 verified, 0 errors).
Lean: both emission regressions pass. The minimal bare-variable reproduction
passes kernel theorems for every string and array, and its Velvet correctness
proof. An additional kernel check of the record-field fixture encounters an
existing
DecidableEqderivation failure for a record containing a synthesizedarray-union; a detached checkout of the exact base reproduces the same error.
That separate backend limitation is unchanged here.
Compatibility
No new syntax, dependency, option, annotation or type representation. The
change only corrects negated array-test ternaries. Proofs depending on the old
reversed mapping must be updated using the normal regeneration workflow.