Conversation
Issue #395 — auto-capture for quotations passed to combinators — is implemented. What changed File: crates/compiler/src/typechecker.rs Change: analyze_captures: Extended to fire auto-capture when the body has more concrete inputs than the expected quotation type provides. Three sub-cases: (a) expected is empty (strand.spawn, unchanged), (b) expected has concrete inputs and body has more (new — list.fold etc.), (c) expected has only row-variable inputs (strand.weave — no capture, unify). infer_quotation: Closure pop loop now unifies each popped type against the expected capture type (soundness fix). ──────────────────────────────────────── File: tests/integration/src/test-auto-capture.seq Change: New — 5 integration tests: fold+capture, map+capture, filter+capture, each+capture, Horner polynomial ──────────────────────────────────────── File: examples/projects/sss.seq Change: Rewritten eval-poly: manual recursive loop → list.fold with auto-captured evaluation point. Removed eval-poly-loop. Updated header comments. Secret reconstruction still passes. What works - list.fold with one auto-captured value: fold body receives (acc, coeff, captured_x) with captured value on top - list.map with captured offset: 100 [ i.+ ] list.map auto-captures 100 - list.filter with captured threshold: 4 [ >aux aux> i.< ] list.filter auto-captures 4 - list.each with captured value - Auto-capture + aux-in-quotations compose: stash the captured value on quotation-level aux while doing fold work - strand.spawn existing auto-capture: unchanged, still works - strand.weave yield quotations: unchanged, still pass - Shamir's Secret Sharing: eval-poly rewritten, "SUCCESS — secret recovered!" confirmed Key convention Captured values appear on top of the combinator-provided values at runtime. The body must be written accordingly: ( acc coeff captured_x ) with x on top for a fold body that auto-captures one value.
Code Review — Auto-Capture for Combinator Quotations (#395)Overall this is solid work. The three-case logic ( Bug: misleading polynomial comment in
|
┌──────────────────────────────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Item │ Fix │
├──────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Polynomial comment bug │ Changed to p(x) = 2*x^2 + x + 4 (coefficients high-to-low: [2, 1, 4]) — matches the assertion and Horner trace │
├──────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Unnecessary >aux aux> in filter │ Removed — i.< works directly on ( elem threshold ) │
│ test │ │
├──────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ calculate_captures alignment gap │ Added TODO documenting the gap — topmost types not verified against expected inputs. Noted it's caught │
│ │ downstream but clearer here │
├──────────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Scoped use import │ Moved extract_concrete_types to module-level use crate::capture_analysis::{calculate_captures, │
│ │ extract_concrete_types} │
└──────────────────────────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
Code Review — PR #400: auto captureOverall this is a well-structured feature addition. The PR description is thorough, the code is well-commented, and the real-world validation via Potential Bugs / Soundness Gaps1. The three-arm let expected_is_empty = matches!(expected_effect.inputs, StackType::Empty);
let should_capture = if expected_is_empty {
!body_inputs.is_empty()
} else if !expected_inputs.is_empty() { // concrete inputs exist
body_inputs.len() > expected_inputs.len()
} else {
false // row-variable-only
};The guard let expected_concrete_count = expected_inputs.len();
let body_concrete_count = body_inputs.len();
let should_capture = body_concrete_count > expected_concrete_count
&& !matches!(expected_effect.inputs, StackType::RowVar(_));This is equivalent today but more robust to structural changes in 2. Topmost-type alignment not verified in The TODO you left is real and worth acting on before this merges — or at least promoting to a tracked issue. The current flow is:
This means a user who writes a body like 3. Error message position index may be confusing (typechecker.rs ~line 1319–1326) for (i, expected_type) in captures.iter().enumerate().rev() {
let (new_stack, actual_type) = self.pop_type(...)?;
unify_types(...).map_err(|e| {
format!("closure capture type mismatch at position {}: ...", i, ...)
})?;
Code Quality4. Comment says "two sub-cases" but PR description says "three" The inline comment at line ~2129 says "Two sub-cases: (a)…(b)…" but the PR description lists three. The code actually handles three distinct paths ((a) empty, (b) concrete, (c) row-var). Update the inline comment to say "Three sub-cases" to match the PR description and the actual logic. 5. The pattern of stashing Test Coverage6. This only catches crashes, not correctness regressions. Since 7. No negative tests for the new There is no test for the case where a body has fewer inputs than the combinator expects (should fall through to the unification/error path). A test verifying that a type-mismatched quotation produces a compile error would give confidence that the unification error path still fires correctly. 8. No test for multiple simultaneous captures All five integration tests capture exactly one value. A test capturing two values (e.g., a fold that captures both a multiplier and an offset) would exercise the multi-capture path in 9. No regression test for The PR description notes Minor10. The comment accurately describes the workaround and flags it as future work for Issue #395. Since this PR is the Issue #395 implementation, update the comment to refer to "a future multi-capture fold" or a new tracking issue so it does not confuse readers who just landed this PR. Summary
The core logic in |
Code Review — Auto-capture for combinator quotations (Issue #395)Overall this is a solid, well-scoped feature. The approach is sound, the sss.seq rewrite is noticeably cleaner, and the test spread across fold/map/filter/each is a good baseline. A few things worth looking at before merge: Potential Bug —
|
┌───────────────────────────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ Item │ Fix │ ├───────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ test-horner-poly doesn't │ Added comment explaining why: eval-poly uses GF(256) field arithmetic and is validated end-to-end by the Shamir │ │ exercise eval-poly │ example's "SUCCESS" assertion during just ci. The inline Horner test validates the auto-capture mechanism itself. │ ├───────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ "Two sub-cases" vs three │ Changed to "Three branches" with all three listed explicitly in the comment │ │ branches │ │ ├───────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ Error message position │ Added (0 = bottommost) to disambiguate the index convention │ │ direction │ │ ├───────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ test-each-capture intent │ Added explicit comment: "No value to assert — this test only checks that auto-capture compiles and executes without │ │ unclear │ crashing" │ └───────────────────────────────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ The reviewer also asked for a negative test for the alignment check. The alignment check in calculate_captures only fires on concrete type mismatches (type variables pass through), and in practice the combinator signature types are type variables (Acc, T), so the check won't fire in normal combinator usage. It's a defense against edge cases where someone writes a manually-typed quotation. Rather than adding a test for a path that's nearly impossible to reach through normal code, the check exists as a safety net and is documented as such.
Code Review - PR 400: auto capture (Issue 395)This is a solid, well-scoped feature. The three-branch Below are observations in rough priority order. Highest priority1.
Suggested addition: 2. No negative tests for the new soundness check Both the topmost-type alignment check in Moderate priority3. This catches crashes only. Even a minimal runtime check - accumulating into an aux and checking its value - would add meaningful coverage. If the language makes this impossible right now, a comment explaining why and linking a follow-up issue is better than silent omission. 4. No test for multiple simultaneous captures All five tests capture exactly one value. A test that captures two values (e.g., a fold body that captures both a multiplier and an offset) would exercise the multi-capture slice in Minor5. No-op Stashing and immediately retrieving 6. Type-variable exemption in The exemption ( What is working well
The main asks before merging: a direct |
Issue #395 — auto-capture for quotations passed to combinators — is implemented.
#395
What changed
File: crates/compiler/src/typechecker.rs
Change: analyze_captures: Extended to fire auto-capture when the body has more concrete inputs than the expected quotation type provides. Three sub-cases:
type
(soundness fix).
────────────────────────────────────────
File: tests/integration/src/test-auto-capture.seq
Change: New — 5 integration tests: fold+capture, map+capture, filter+capture, each+capture, Horner polynomial
────────────────────────────────────────
File: examples/projects/sss.seq
Change: Rewritten eval-poly: manual recursive loop → list.fold with auto-captured evaluation point. Removed eval-poly-loop. Updated header comments.
Secret
reconstruction still passes.
What works
Key convention
Captured values appear on top of the combinator-provided values at runtime. The body must be written accordingly: ( acc coeff captured_x ) with x on top
for a fold body that auto-captures one value.