Skip to content

fix(verify): correct modifies-array call-site argument binding#7

Open
kondylidou wants to merge 1 commit into
strata-org:mainfrom
kondylidou:fix/partition-modifies-global-threading
Open

fix(verify): correct modifies-array call-site argument binding#7
kondylidou wants to merge 1 commit into
strata-org:mainfrom
kondylidou:fix/partition-modifies-global-threading

Conversation

@kondylidou

Copy link
Copy Markdown
Contributor

Summary

gen_smt_vcs_boole crashed with a hard type error on any Boole program
where a caller modifies an array-typed global and calls a callee that
also modifies that global and takes a plain int parameter referenced
in its own ensures clause (e.g. Quicksort/Partition). The callee's
int formal was getting bound to the caller's array argument instead of
the actual int argument, producing errors like:

Application type mismatch: The argument «A@1» has type SmtArray Int Int
but is expected to have type Int in the application GE.ge «A@1»

Root cause

CallArg.replaceInArgs (Strata's Core/Statement.lean) rewrites a call's
argument list with type-checked expressions by walking it and consuming
one resolved expression per .inArg. But getInputExprs — which produced
those resolved expressions — emits one expression per .inArg and per
.inoutArg (modifies-globals are threaded through as .inoutArg).
replaceInArgs silently skipped .inoutArg without consuming its slot,
so every argument after the first modifies-global shifted one position.

This was already fixed upstream (strata-org/Strata@0de296da) as a side
effect of an unrelated typechecker-soundness proof

Changes

  • Bump the pinned Strata revision to current origin/main, which pulls
    in the upstream fix.
  • That bump also drags in a month of unrelated churn, two pieces of which
    broke this repo — both fixed here:
    • Option MetadataAnn (replacing the old single-purpose ReachCheck
      category) got threaded onto most Core DDM statement/command ops.
      Updated ~25 affected pattern matches in StrataBoole/Verify.lean.
    • Three bitvector operator tokens were renamed off the
      identifier-collision path (>>sashr, <s/<=s/>s/>=s
      slt/sle/sgt/sge). Updated bitvector_ops.lean.
  • Regenerated stack_array_based.lean's #guard_msgs output for
    incidental obligation-label renumbering from the version bump.
  • Added quicksort.lean: a permanent, fully-proved (no sorry)
    regression test for the modifies-array + call-site scenario.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Comment thread StrataBoole/Verify.lean Outdated
return modifiesArgs ++ readOnlyArgs

/-- `@[reachCheck]` on `assert`/`cover` marks a reachability check. Core's DDM grammar
used to have a dedicated `ReachCheck` category for this; it was folded into the

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, but comments should be stateless

Comment thread StrataBooleTest/quicksort.lean Outdated
Regression test for a caller/callee pair where the callee both `modifies` an
array-typed global (threaded through the call site as an extra `inout`
argument) and takes a plain `int` input that is referenced in its own
`ensures` clause. This combination used to make `gen_smt_vcs_boole` mis-bind

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same

…rata

quicksort.lean and similar Boole programs (a caller `modifies` an array
global and calls a callee that both `modifies` that same array and takes
a plain `int` parameter referenced in its own `ensures`) crashed
`gen_smt_vcs_boole` with a hard type error: the callee's `int` formal got
bound to the caller's array argument instead.

Root cause: `CallArg.replaceInArgs` (Strata's Core/Statement.lean) rewrites
a call's argument list with type-checked expressions by walking the arg
list and consuming one resolved expression per `.inArg`. But
`getInputExprs` (which produced those resolved expressions) emits one
expression per `.inArg` *and* per `.inoutArg`, since modifies-globals are
threaded through as `.inoutArg`. `replaceInArgs` skipped over `.inoutArg`
without consuming its slot, so every argument after the first modifies
global got shifted by one position.

This was already fixed upstream (strata-org/Strata commit 0de296da) as
part of an unrelated typechecker-soundness proof, but Strata-Boole's
pinned revision predated it by about an hour. Bumping the pin to current
`origin/main` pulls in a month of otherwise-unrelated churn, most
notably: `Option MetadataAnn` replacing the single-purpose `ReachCheck`
category and being threaded onto most Core DDM statement/command ops
(arity shift at ~25 call sites in Verify.lean), and three operator tokens
renamed off the identifier-collision path (`>>s`->`ashr`,
`<s/<=s/>s/>=s`->`slt/sle/sgt/sge`) which broke `bitvector_ops.lean`'s
literal syntax. Both are fixed here; `stack_array_based.lean`'s
`#guard_msgs` output is regenerated for the resulting label-numbering
drift.

Adds quicksort.lean as a permanent regression test for the modifies-array
+ call-site scenario, fully proved (no `sorry`).
@kondylidou
kondylidou force-pushed the fix/partition-modifies-global-threading branch from 8aed202 to bae1d9d Compare July 21, 2026 20:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants