You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 02a5914
Browse filesBrowse the repository at this point in the historyBrowse files
feat(borrow): CORE-01 Slice D (#177 pt3) — reject @linear capture by closure at borrow check (#397)
## Summary
Tighter integration with the quantity checker for captured linears: the
borrow checker now refuses to let a closure capture a @linear (QOne)
binding. Pre-Slice-D, this case fell only to the quantity checker (which
scales lambda captures by QOmega and emits
\`LinearVariableUsedMultiple\`); now the same constraint fires earlier
in the pipeline (Typecheck → Borrow → Quantity) with a diagnostic that
points at the **lambda span** — the actual capture site — rather than
the downstream "used multiple times" message.
## Mechanism
- New \`state.linear_bindings\` tracks sym-ids of @linear bindings
declared in the current function: explicit \`@linear\` annotations on
\`let\`-statements and \`let\`-expressions, \`@linear\` function params,
and \`let x: Cmd[T] = …\` (linear-by-construction per ADR-002).
- At \`ExprLambda\`, the free-var walk now also looks up each captured
name's symbol and rejects with \`LinearCapturedByClosure(name,
lambda_span)\` if the sym-id is in \`linear_bindings\`.
- The Shared-borrow creation for non-linear captures is unchanged.
## Refs
- #177 (CORE-01 pt3)
- Third of three small slices being landed today; #395 (ref-to-ref) and
#396 (Slice C') are in flight. **Slice C-full (Polonius) is being handed
off to a separate Claude** — prompt incoming separately.
## Test plan
- [x] \`dune runtest --force\` — 327 → **330 tests, 0 failures**
- [x] 3 new e2e fixtures + handlers:
- \`slice_d_captured_linear_let_rejected.affine\` — \`@linear let x;
fn() => x + 1\` → \`LinearCapturedByClosure("x", _)\`
- \`slice_d_captured_linear_param_rejected.affine\` — \`fn foo(@linear
y: Int) { let f = fn() => y + 1; … }\` → \`LinearCapturedByClosure("y",
_)\`
- \`slice_d_captured_nonlinear_ok.affine\` — anti-regression: non-linear
capture must still pass
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0 commit comments