fix(emit-js): don't emit runtime imports for macro-only refers#3
Merged
Conversation
A `:refer`'d name that resolves to a macro is compile-time only — it's
expanded away and never referenced at runtime, and the target module
emits no runtime export for it. Emitting it in `import { … }` produces
ESM that throws "does not provide an export named X" in any consumer
that isn't bundled (e.g. test files loaded via dynamic import). The
chrome layer only worked because its bundler tree-shook the dead import.
emit-module-header now drops macro refers (checked against program-macros)
and omits the import line entirely when a require's refers are all macros.
Verified: active suite 1377/1377; gjoa chrome bundle + tests unaffected.
tompassarelli
added a commit
that referenced
this pull request
Jun 16, 2026
Turtle #3. Adds the claims->datum->source reverse path that did not exist anywhere in beagle, and a gate proving a program round-trips through its CNF claim graph losslessly: - datum<->claims identity: 1100/1100 forms across the gjoa corpus - text-is-a-view: 97/97 files render to idiomatic beagle that re-reads identically (un-desugars [..]->(#%brackets ..), {..}->(#%map ..)) - type annotations (:- T) survive for free as reader tokens bin/beagle-roundtrip exposes the gate + --emit-edn (reader claims for Fram) and --verify modes. The reader-datum projection is verbose-but-lossless (source of truth); emit-claims stays compact-but-lossy (queries).
tompassarelli
added a commit
that referenced
this pull request
Jun 18, 2026
…ol return, quasiquote quote, variant-delete, self-doc delete) rename.sh §9: parameterized defunion name renames + annotations cascade; defprotocol method return type cascades; (quote ..) inside a quasiquote stays inert data. delete.sh §4-5: a defunion variant is refused (not a top-level form, no false success); a self-documented def is deletable (its own doc-comment is pruned, not an orphan).
tompassarelli
added a commit
that referenced
this pull request
Jun 21, 2026
…scape-across-fn) Closes soundness hole-class #3 (escape across the fn boundary) from beagle-2's adversarial boundary map: a fn RETURNING a compound-keyed map (or a `(set var)` over a compound-typed param) was read NATIVE by the caller because rep-selection was intraprocedural + per-node-table only (bare var-refs and call results carry no rep). Two additions to classify-rep: - TYPE-DIRECTED dispatch: an expression whose node-type is a concrete compound-keyed Map / compound-elem Set classifies hmap/hset directly. This catches annotated fn returns (`build-index :- (Map (Vec Int) Keyword)`) and any typed expr — the caller's get/contains/count now route to HAMT ops. - BINDING-TYPE ENV (current-type-env): a var-ref resolves to its declared type (param `:-` annotation / let value type) via arg-type, so `(set paths)` with paths :- (Vec (Vec Int)) sees the compound element and routes to hamtSet. Seeded at defn/fn/arity params (with-param-envs) + composes with rep-env. - rep-env now also seeded from param types (a param :- (Map compound ..) reads as hmap inside the body). Real-program evidence: bjs-bench/programs/structdiff.bjs (pure-value diff/merge = Eddy skip-if-unchanged at lib scale) goes 5/7 -> 7/7 — distinct-paths (value dedup over a compound param) and cross-fn compound-map lookup both flip GREEN. No regression: active 1474/1474, gated JS (emit-js 147, fixtures, jst, exec-oracle) + behavioral 78 all green. Still provably-compound predicate; the Any/records/unions flip (#1,#2,#5,#6) is the next commit.
tompassarelli
added a commit
that referenced
this pull request
Jun 21, 2026
…HAMT Closes the last soundness hole-class (#4 runtime dedup) from beagle-2's boundary map. The runtime collection builders no longer emit native ARRAYS for sets (a pre-existing set-builder bug) and route to value-dedup HAMT when the element type is compound: coll-kind helper: 'set | 'vec | 'map | 'unknown, seeing through conj/into/disj to the underlying collection (so a native Set/conj-result isn't mistaken for an array). conj : value-set -> hamtSetAdd fold ; native set -> new Set([...c, x]) (a Set, not [...c,x]) ; vec -> [...c,x]. into : value-set -> xs.reduce(hamtSetAdd, target) ; native set -> new Set([... target, ...xs]) ; vec -> spread. count : native branch now dispatches on coll-kind -> set:.size / map:Object.keys ().length / else:.length, so (count (conj #{..} x)) is .size not .length (was undefined). frequencies : compound elements -> value-keyed hamtMap (was native object -> "[object Object]" collisions). group-by left native (its key type comes from f's return, not reliably inferable — documented residual). Verified vs Clojure shape: conj/into on scalar+compound sets (3/1/4/2), frequencies compound/scalar (2/2). rep-soundness +4 = 24/24; active 1484/1484, gated JS (emit-js 147, exec-oracle 7, ...) + behavioral 78 green. ALL 6 hole-classes now closed: #1 records, #2 unions, #3 escape-across-fn, #4 runtime dedup, #5 heterogeneous, #6 cross-rep equality.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A
:refer'd name that resolves to a macro is compile-time only — it's expanded away and never referenced at runtime, and the target module emits no runtime export for it. Emitting it inimport { … }produces ESM that throwsdoes not provide an export named Xin any consumer that isn't bundled (e.g. test files loaded via dynamicimport()).Until now this was masked: the chrome layer's bundler tree-shakes the dead import. But an unbundled consumer (the integration-test runner loads compiled test files directly) hits the error.
emit-module-headernow filters each require's refer list againstprogram-macros(which includes imported macros), dropping macro names. If a require's refers are all macros, no import line is emitted at all.Verification
import { by_id, mi, … } from './macros.js'(dead, was bundler-stripped) is now simply not emitted