Claude/pr351 no techdebt by hyperpolymath · Pull Request #355 · hyperpolymath/affinescript · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 56 additions & 8 deletions lib/borrow.ml
22 changes: 22 additions & 0 deletions test/e2e/fixtures/slice_b_new_borrow_still_protects.affine
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2026 Jonathan D.A. Jewell
//
// CORE-01 pt3 Slice B / #177 anti-regression: after `r = &y`, the
// NEW borrow on `y` must still protect `y` while `r` is live. A
// buggy Slice B that dropped the ref-binding but failed to re-bind
// to the new borrow would silently accept `y = 10` below — the
// borrow-graph would lose track of who holds &y. With correct
// Slice B, `(r, &y)` is in ref_bindings, the borrow on `y` is in
// state.borrows, and the assignment to `y` is rejected as
// MoveWhileBorrowed. Expected: Error MoveWhileBorrowed.

module SliceBNewBorrowStillProtects;

fn still_protected() -> Int {
let mut x = 1;
let mut y = 2;
let mut r = &x;
r = &y;
y = 10;
*r
}
24 changes: 24 additions & 0 deletions test/e2e/fixtures/slice_b_nll_expires_new.affine
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2026 Jonathan D.A. Jewell
//
// CORE-01 pt3 Slice B / #177: after `r = &y`, the NLL last-use
// machinery must track the NEW borrow (on `y`), not the stale old
// one (on `x`). Without Slice B, the ref-binding entry stays
// `(r, &x)`, so when NLL expires `r` after its last use it ends the
// wrong borrow — leaving the new borrow on `y` alive and
// spuriously rejecting the later `y = 10`. With Slice B, the entry
// is `(r, &y)` post-reassignment, NLL expires the correct borrow,
// and both `x = 5` and `y = 10` succeed. Expected: Ok.

module SliceBNllExpiresNew;

fn nll_after_reassign() -> Int {
let mut x = 1;
let mut y = 2;
let mut r = &x;
r = &y;
let z = *r;
x = 5;
y = 10;
x + y + z
}
22 changes: 22 additions & 0 deletions test/e2e/fixtures/slice_b_outer_assign_releases_old.affine
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2026 Jonathan D.A. Jewell
//
// CORE-01 pt3 Slice B / #177: flow-sensitive escape via `outer = &y`.
// Pre-Slice-B, the borrow held by `r` on `x` was never released when
// `r` was re-assigned to `&y` — so `x = 10` was rejected as
// MoveWhileBorrowed even though `r` no longer pointed at `x`. With
// Slice B, the assignment `r = &y` ends the held borrow on `x` and
// re-binds `r` in the ref-graph to the freshly-created borrow on `y`,
// so the subsequent write to `x` is legal. Expected: Ok.

module SliceBOuterAssignReleasesOld;

fn outer_reassign() -> Int {
let mut x = 1;
let mut y = 2;
let mut r = &x;
let z = *r;
r = &y;
x = 10;
*r + x + z
}
39 changes: 39 additions & 0 deletions test/test_e2e.ml
Loading