Repository navigation
fix(hy-check): enforce freeze and loan windows across defer and call-arg moves (#98) - #99
sonson0910 wants to merge 1 commit into
Conversation
8385418 to
5b1ade0
Compare
|
Triage (2026-10-15, AI maintainer): defer soundness (#98 — A1b/A7 freeze and A2/A3 windows bypassed through Stmt::Defer) is real and your reproduction is precise. Queued in the conveyor after the current checker batch; pr-101's for_depth machinery touches the same emitter neighborhood so expect a small seam. No action needed from you. |
5b1ade0 to
e588de3
Compare
|
Thank you for the triage note! Proactively rebased |
|
Triage (2026-10-15, AI maintainer, post-CI-repair): updated: pr-223 is a fresh rebased take on the same issue #98 defer/call-arg freeze — both verified together, stronger coverage lands, both credited. Your +406 test surface is the deeper half on paper; hole-by-hole decides. |
c1751cc to
4f29c34
Compare
4f29c34 to
e633be1
Compare
|
Rebased onto latest Payout Wallets:
|
e633be1 to
e0d9d93
Compare
|
Recon (session-15/2-e): issue #98 is still open on main — |
e0d9d93 to
c8ccbb7
Compare
31415e5 to
d9c8e83
Compare
Rebase & Prior-Art / Superset Cross-Reference (
|
d9c8e83 to
94e4d79
Compare
|
Rebased onto latest
|
94e4d79 to
0ad0332
Compare
c79eddb to
e465094
Compare
e465094 to
ac34cdd
Compare
|
Thank you for this careful PR, @sonson0910 — the four-hole analysis of Closing as subsumed: every scenario this PR pins is already rejected on current
What landed instead (your PR heads
Issue #98's report is fully covered by the checks above; the maintainer may close it with this verification. Thanks again — your freeze-window model in this PR is visibly the ancestor of what #421 shipped. |
Fixes #98
Relates to #5
Summary
In Go,
defer f(args...)evaluates its receiver and arguments at thedeferstatement (capturing reference headers/pointers/handles) and executesfat function exit — after all subsequent statements in the function.Previously,
hy-checktreatedStmt::Deferpurely at its lexical statement index and had noStmt::Defer/Stmt::Exprmove handling:defer:m := map[string]int{"init": 0}; defer audit(m); task worker(move m, done)(andw := flate2.new_writer(1, 6); defer w.write("late"); w.finish()) rancheck_usesat thedeferline beforemwas moved orwwas consumed, accepting with0 diagnosticsand racing at function exit (WARNING: DATA RACEundergo run -race).deferand call arguments (collect_move_operands):walk::own_usesmarkedExpr::Moveoperands asvia_move: true(exempting them fromcheck_uses), butStmt::DeferandStmt::Exprdid not invokemark_move_in_value/check_non_owned_move, andcollect_move_operandsdid not recurse intoExpr::Callarguments (m2 := id(move m); task worker(move m2); m["main"] = 2).defer:walk::flattenrecordedlast_useof bindings referenced insideStmt::Deferat thedeferstatement index rather thanfn_end, andStmt::Deferpassedloop_end: Nonetoprocess_call/lend_handle_args. Thuss := &m["a"]; defer bump(s); m["b"] = svc{count: 2}anddefer serde_json.to_string_pretty(doc); doc.set("k", 1)ended their loan windows at thedeferline instead of function exit.Changes
compiler/crates/hy-check/src/walk.rs: Record binding uses insideStmt::Deferand extend theirlast_usetofn_end(out.next.saturating_sub(1)) inflatten().compiler/crates/hy-check/src/model.rs:deferred_usesandbinding_depthtoFnState.Expr::Callcallee and arguments incollect_move_operands.compiler/crates/hy-check/src/freeze.rs:binding_group,scoped_binding_group, andprocess_defer_moves.mark_move, checkst.deferred_usesagainst the moved/consumed binding's alias +may_sharegroup and emitHYB-E3003(A1b/A7).compiler/crates/hy-check/src/loans.rs:lend_handle_argsand inline&m[k]map-slot argument loans toloop_end(which isSome(fn_end)forStmt::Defer).non_owned_originfrom nestedmoveoperands viafirst_moved_non_owned.compiler/crates/hy-check/src/lib.rs&closures.rs:Some(fn_end)toprocess_callforStmt::Defer, process moves inStmt::DeferandStmt::Expr, and add unit tests covering all six soundness regressions.Verification
cargo test --workspace(all unit & integration tests pass)python3 tools/corpus_harness.py(27/27 verdict agreement)python3 tools/differential_loop.py(10/10 accept, 17/17 reject — full agreement)python3 tools/managed_gate.py(PASS)