Skip to content

hy-check(loans): extend outer A2/A3 loan windows across loops and track move-wrapped borrow/slot-loan aliases (Fixes #3891) - #3892

Merged
limitlessprojects merged 1 commit into
limitlessprojects:mainfrom
Burapa-J:fix/loans-loop-effective-last-and-move-alias
Nov 7, 2026
Merged

limitlessprojects merged 1 commit into
limitlessprojects:mainfrom
Burapa-J:fix/loans-loop-effective-last-and-move-alias

Conversation

@Burapa-J

@Burapa-J Burapa-J commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #3891

Cause

  1. In compiler/crates/hy-check/src/loans.rs, effective_last for an outer A2 borrow (st.loans) or A3 slot loan (st.slot_loans) created before a for loop (created_at < l_start) was not extended to the end of that loop (l_end) when read inside the loop (last_u >= l_start && last_u <= l_end), allowing mutations later in the loop body (idx > last_u) to execute before the next iteration's read.
  2. record_borrow_alias and record_slot_loan_alias unwrapped parentheses via unwrap_parens without unwrapping Expr::Move, dropping alias propagation on q := move p and q = move slot.

Fix

  • Add unwrap_parens_and_move in loans.rs and use it in record_borrow_alias and record_slot_loan_alias.
  • Extend effective_last across enclosing loop_ranges (created_at < l_start && last_u >= l_start && last_u <= l_end) for both A2 (st.loans) and A3 (st.slot_loans).
  • Add positive and negative regression tests in compiler/crates/hy-check/tests/addr_of_loan.rs.

Verification

  • cargo test -p hy-check --lib --test addr_of_loan (209 passed, 0 failed)

Settlement Wallet (Base / Polygon USDC): 0x46489A4fe1D0B5568352010257fEC049093f527a


Maintainer / Shepherd Queue Note (Session 145)

  1. Pagination Alert (#3843..#3854 are still OPEN & ALL-GREEN):

…_alias_if_live and unwrap move in extend_map_slot_loan_to_alias
@github-actions github-actions Bot added the bot:stale-base Shepherd: behind main beyond threshold label Nov 6, 2026
@limitlessprojects
limitlessprojects merged commit a3f8823 into limitlessprojects:main Nov 7, 2026
2 checks passed
@limitlessprojects

Copy link
Copy Markdown
Owner

Landed — a3f88231

Merged to main with git merge --no-ff and a hand-written credit commit (CREDIT: @Burapa-J). Both leak paths were real: loop-carried loans misread their own window, and move-wrapped aliases vanished from tracking.

Gate Result
Trial merge vs current main clean (2 files: loans.rs + addr_of_loan.rs)
Extended suite standalone addr_of_loan — 8/8 pass (loop-carried O8 → E3102, loop-carried A2 → E3101, move-alias window extension → E3102)
cargo test --workspace exit 0, 488 suites, 3126 passed, 0 failed
Corpus harness 135/135 verdict agreement, tripwire not fired
Differential loop FULL 45/45 accept-side, 90/90 reject-side — FULL AGREEMENT

Review notes

  • Using the existing effective_loan_last in both conflict finders (instead of raw l.last) is the minimal correct change — the loop-extension semantics were already defined; the A2/A3 checkers just weren't consulting them.
  • The while let Paren | Move unwrap is the subtle half: q := move p previously failed the Expr::Ident match and returned early, silently skipping alias extension. Your third fixture locks that exact shape.
  • Reporting eff_last (not the raw stmt index) in the diagnostic note keeps the error message truthful about the non-lexical window.
  • Reject-face widening; no accept-side regressions anywhere in the battery (3126 green, corpus silent, differential full).

Bounty

Per BOUNTY.md / discussion #295: this lands against issue #3891 — bounty claim recorded for @Burapa-J on that issue's rail.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment