Skip to content

HOF dispatch PR 4: lift inline lambdas Phase 1 to cross-engine#284

Merged
danieljohnmorris merged 2 commits into
mainfrom
fix/lambdas-cross-engine
May 15, 2026
Merged

HOF dispatch PR 4: lift inline lambdas Phase 1 to cross-engine#284
danieljohnmorris merged 2 commits into
mainfrom
fix/lambdas-cross-engine

Conversation

@danieljohnmorris
Copy link
Copy Markdown
Collaborator

Summary

Phase 1 of the inline lambda work (#247) shipped tree-only: a (params>ret;body) literal lifts to a synthetic __lit_N top-level decl, and any HOF that consumed it had to be tree-only because VM and Cranelift didn't dispatch HOFs yet. That gating made sense at the time, but it's stale now.

With the recent HOF chain landed - FnRef NaN-tagging in #274, native map dispatch in #277, flt/fld/flatmap in #278, the tree-bridge for grp/uniqby/srt-2arg/partition in #279, and closure-bind ctx forwarding in #280 - inline lambdas-as-args produce identical output on tree, VM, and Cranelift. This PR makes the guarantee explicit:

  • Lifts engine-skip: vm from examples/inline-lambda.ilo so the example harness runs all four srt / flt / fld cases on both tree and VM.
  • Adds tests/regression_lambdas_cross_engine.rs with 15 cases pinning inline lambdas as args to map, flt, fld, srt, grp, uniqby, partition, flatmap across tree/VM/Cranelift. Covers both 2-arg and 3-arg ctx-bind forms plus empty-list short-circuit paths.

Phase 2 closure capture (#265) is still tree-only - examples/inline-lambda-capture.ilo keeps its engine-skip: vm jit cranelift line, and the cross-engine tests deliberately use the ctx form to keep coverage flat. Phase 2 cross-engine support is the next follow-up in the chain.

Repro before / after

examples/inline-lambda.ilo by-dist [-3,1,-5,2] on VM:

Before: skipped by the example harness (gated engine-skip: vm).

After: prints [1, 2, -3, -5] on tree, VM, and Cranelift.

What's in the diff

  • test: cross-engine coverage for inline lambdas as HOF args - 15 regression cases in tests/regression_lambdas_cross_engine.rs, each running tree / VM / Cranelift and asserting identical output.
  • example: lift vm skip from inline-lambda.ilo - drops the now-stale engine-skip: vm annotation, so the example harness exercises VM dispatch on every assertion in the file.

Test plan

  • cargo test --release --features cranelift --test regression_lambdas_cross_engine (15 passed)
  • cargo test --release --features cranelift --test examples_engines (full pass, inline-lambda.ilo now runs on VM)
  • cargo test --release --features cranelift (full suite green, 0 failed)
  • cargo fmt --all
  • cargo clippy --release --features cranelift --all-targets -- -D warnings

Follow-ups

  • Phase 2 closure capture (inline-lambda-capture.ilo) needs the synthetic decl's captures plumbed through VM / Cranelift before its engine-skip line can come off. Tracked separately as the Phase 2 cross-engine PR.

Pins Phase 1 inline lambdas (the (params>ret;body) literal lifted to
synthetic __lit_N decls) as arguments to every HOF that now has
cross-engine dispatch: map, flt, fld, srt, grp, uniqby, partition,
flatmap. Covers both 2-arg and 3-arg ctx-bind forms on tree, VM,
and Cranelift.

The 3-arg form is how Phase 1 lambdas thread external state without
closure capture; Phase 2 capture is still tree-only, so these tests
use ctx-bind to keep coverage flat across every engine.

Empty-list cases on map/flt/fld pin the dispatcher short-circuit
path before the first OP_CALL_DYN on every engine.
Phase 1 inline lambdas now dispatch identically on tree, VM, and
Cranelift now that FnRef + native HOF dispatch + tree-bridge for
the ctx forms have all landed (#274/#277/#278/#279/#280).
The example harness exercises the lifted lambdas across every
engine, locking in the cross-engine guarantee.

Phase 2 closure capture remains tree-only and stays gated in
inline-lambda-capture.ilo until a follow-up PR.
@codecov
Copy link
Copy Markdown

codecov Bot commented May 15, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@danieljohnmorris danieljohnmorris merged commit 3ca4ef8 into main May 15, 2026
5 checks passed
@danieljohnmorris danieljohnmorris deleted the fix/lambdas-cross-engine branch May 15, 2026 16:16
danieljohnmorris added a commit that referenced this pull request May 15, 2026
- slc / take / drop accept negative indices counting from end (bounds
  clamp), matching at xs i. Closes the quant-trader fencepost and the
  slc xs -np 1 np ergonomics gap (#266).
- Map keys are typed: text or integer. mset m 7 v and mget m 7 work
  directly, no str conversion. Int(1) and Text("1") are distinct.
  Float keys floor to i64; jdmp stringifies numeric keys for JSON (#267).
- Add map / flt / fld to the builtin reference. All HOFs (map, flt,
  fld, srt, grp, uniqby, partition, flatmap) now work cross-engine
  on tree, VM, Cranelift JIT, and AOT (#274 #277 #278 #279 #280 #283).
- New Inline lambdas subsection: Phase 1 literals are cross-engine,
  Phase 2 closure capture is tree-only with automatic fallthrough
  surfacing ILO-R012 on VM and Cranelift (#265 #284).
- AOT-compiled binaries from ilo compile now strip the top-level
  ~/^ wrapper byte-for-byte the same as in-process runners (#281).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant