Skip to content

Compile functions with $-prefixed parameters instead of bailing - #58

Merged
revarbat merged 1 commit into
mainfrom
compile-dollar-params
Jul 31, 2026
Merged

Compile functions with $-prefixed parameters instead of bailing#58
revarbat merged 1 commit into
mainfrom
compile-dollar-params

Conversation

@revarbat

Copy link
Copy Markdown
Member

Summary

  • $-prefixed parameters (e.g. function f($fn) = ...) used to bail compilation of the whole containing declaration; they now compile, binding through ctx.dyn instead of a slot since every reference already compiled to Op::LoadDyn regardless.
  • Same fix also unblocks a FunctionLiteral closure with its own $-param, since compileFunctionLike is shared between plain functions and closures.
  • Positional binding, named binding, and defaults (including the "declared-but-unbound shadows to undef" rule) all route to ctx.dyn consistently for $-params, mirroring the interpreter's existing bindCallArgsInto/applyDefaults behavior.
  • No tail-call-specific handling was needed: every trampoline hop rebinds arguments through the same helper a genuine call uses, and $-var dynamic scoping already threads correctly across hops.

Test plan

  • Rewrote the two tests that asserted the old bail behavior (DollarPrefixedParameterCompiles, ClosureWithDollarParameterNowCompilesToo) to instead prove compilation via the file's existing fast-continue stop-count technique (one of the old assertions turned out to be unreliable regardless of the fix -- nullopt fast-continue forces interpretation for every function, not just the one under test).
  • Added DollarParameterThreadsThroughCompiledTailRecursion -- a $fn parameter threaded through 50,000 compiled tail-recursive hops.
  • Full suite: 681/681 passing.
  • Manual smoke tests (compiled vs interpreted agreement): declared-with-default, positional binding, named override, declared-but-unbound-shadows-to-undef, and deep tail recursion.

🤖 Generated with Claude Code

$-params bind through ctx.dyn (dynamically scoped) rather than a slot,
but every reference to one inside a body already compiled to Op::LoadDyn
regardless of scope visibility -- the only missing piece was binding.
compileFunctionLike now skips declareLocal for a $-param instead of
bailing compilation of the whole function (and, since it's shared,
the whole containing declaration for a closure's own $-param too).
bindCompiledArgs/runCompiledFunctionFromBound route a matched $-param
to childCtx.dyn instead of a slot, for both positional and named
binding, with defaults applied the same way.

No tail-call-specific handling needed: every hop rebinds arguments
through the same helper as a genuine call, and dyn already threads
correctly across tail hops.
@revarbat
revarbat merged commit 16e1cbe into main Jul 31, 2026
3 checks passed
@revarbat
revarbat deleted the compile-dollar-params branch July 31, 2026 04:22
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