A VM-vs-self-host corpus audit during 0.24 prep found the self-hosted interpreter (self_hosted/*.av, compiled to Rust under src/self_host/) lags the other backends on several language features. 0.24 "Divide" closed the tractable ones — Int.div builtin, float-literal lexing inside string interpolation, and replay Unit-output normalization (branch fix-self-host-parity). This issue tracks the two remaining gaps, each a real subsystem rather than a quick patch.
Regen after editing self_hosted/*.av: aver compile self_hosted/main.av --target rust --output self_hosted/out --module-root self_hosted --with-self-host-support --guest-entry runGuestCliProgram --with-replay --policy runtime, then copy self_hosted/out/src → src/self_host/ and cargo build.
1. Higher-order functions (Fn(...) parameters)
Repro: a top-level fn passed as a Fn(...) parameter and called indirectly.
fn dbl(x: Int) -> Int
x * 2
fn applyTwice(f: Fn(Int) -> Int, x: Int) -> Int
f(f(x))
aver run --self-host fails at parse: Expected ',' or ')' in parameter list. Two layers:
- Parser:
skipTypeExpr in self_hosted/domain/parsermatch.av (~L224) handles TkIdent and TkLParen but has no TkFn case, so a Fn(A) -> B parameter type never parses. Add a TkFn branch that skips Fn ( types ) -> ret. (TkFn/TkArrow tokens already exist.)
- Eval:
ValFnRef is created (self_hosted/domain/eval/common.av:12) when an identifier resolves to a fn, but it is never consumed — there is no path to call a value holding a fn-ref. callWithArgs/callWithArgsNormal (self_hosted/domain/eval/core.av:341/348) resolve the callee only as a top-level fn (lookupFnOption) or a builtin, and don't receive env; a call f(x) where f is a local param bound to ValFnRef falls through to callBuiltin("f", …) and fails. Need: when the callee name is a local var bound to ValFnRef, redirect to the referenced fn — in both the named-env path (evalCall) and the slot-env path (evalCallSlot, core.av:807), and likely in the resolver (slot assignment / call-target resolution may reject a param-as-callee).
The self-host is slot-resolved and was not designed for first-class fn values; this is a feature add.
2. Multi-module type / symbol resolution
examples/modules/app.av (and pricing_app.av, app_dot.av) → Argument 1 of 'Console.print': expected String, got E — a cross-module generic type variable E is never instantiated.
examples/refinement/natural_app.av → Unknown identifier 'Refinement' — a depends [...] module prefix is not resolved.
The self-host typechecker/resolver lacks module-aware symbol resolution: it does not load dependency-module signatures, resolve qualified names across modules, or instantiate generics from a cross-module callee's signature. The host compiler does this (src/types/checker/modules.rs); the self-host has only a basic FnStore.
Verification
- Corpus parity: run every non-interactive
examples/**.av through aver run vs aver run --self-host and diff stdout. After 0.24 batch 1 this is 21/25; these four module/refinement cases are the remaining divergences (target 25/25).
- Regen gate:
AVER_SELF_HOST_REGEN=1 cargo test --test rust_self_host_regen -- --ignored.
A VM-vs-self-host corpus audit during 0.24 prep found the self-hosted interpreter (
self_hosted/*.av, compiled to Rust undersrc/self_host/) lags the other backends on several language features. 0.24 "Divide" closed the tractable ones —Int.divbuiltin, float-literal lexing inside string interpolation, and replay Unit-output normalization (branchfix-self-host-parity). This issue tracks the two remaining gaps, each a real subsystem rather than a quick patch.Regen after editing
self_hosted/*.av:aver compile self_hosted/main.av --target rust --output self_hosted/out --module-root self_hosted --with-self-host-support --guest-entry runGuestCliProgram --with-replay --policy runtime, then copyself_hosted/out/src→src/self_host/andcargo build.1. Higher-order functions (
Fn(...)parameters)Repro: a top-level fn passed as a
Fn(...)parameter and called indirectly.aver run --self-hostfails at parse:Expected ',' or ')' in parameter list. Two layers:skipTypeExprinself_hosted/domain/parsermatch.av(~L224) handlesTkIdentandTkLParenbut has noTkFncase, so aFn(A) -> Bparameter type never parses. Add aTkFnbranch that skipsFn ( types ) -> ret. (TkFn/TkArrowtokens already exist.)ValFnRefis created (self_hosted/domain/eval/common.av:12) when an identifier resolves to a fn, but it is never consumed — there is no path to call a value holding a fn-ref.callWithArgs/callWithArgsNormal(self_hosted/domain/eval/core.av:341/348) resolve the callee only as a top-level fn (lookupFnOption) or a builtin, and don't receiveenv; a callf(x)wherefis a local param bound toValFnReffalls through tocallBuiltin("f", …)and fails. Need: when the callee name is a local var bound toValFnRef, redirect to the referenced fn — in both the named-env path (evalCall) and the slot-env path (evalCallSlot, core.av:807), and likely in the resolver (slot assignment / call-target resolution may reject a param-as-callee).The self-host is slot-resolved and was not designed for first-class fn values; this is a feature add.
2. Multi-module type / symbol resolution
examples/modules/app.av(andpricing_app.av,app_dot.av) →Argument 1 of 'Console.print': expected String, got E— a cross-module generic type variableEis never instantiated.examples/refinement/natural_app.av→Unknown identifier 'Refinement'— adepends [...]module prefix is not resolved.The self-host typechecker/resolver lacks module-aware symbol resolution: it does not load dependency-module signatures, resolve qualified names across modules, or instantiate generics from a cross-module callee's signature. The host compiler does this (
src/types/checker/modules.rs); the self-host has only a basicFnStore.Verification
examples/**.avthroughaver runvsaver run --self-hostand diff stdout. After 0.24 batch 1 this is 21/25; these four module/refinement cases are the remaining divergences (target 25/25).AVER_SELF_HOST_REGEN=1 cargo test --test rust_self_host_regen -- --ignored.