fix(gen-js,gen-ts): a reference nobody checked became a ReferenceError at import - #4529
Merged
Merged
Conversation
Contributor
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
Contributor
…r at import Closes #4528 `const_value` answered every bare identifier with `js_name(name)` under a comment that said "a reference to a const declared above". The comment was the only thing checking. Three shapes in the corpus walked through it and produced artifacts that throw before a single line of them runs: - a name the backend had itself refused to emit, - a name declared further down the file, which `const` does not hoist into a usable state, - a primitive type name used where a value was expected. `node --check` cannot see any of these -- the module is syntactically perfect. Only `import` reaches them, and it reaches them all at once, so one unbound identifier costs the whole module. `Bound` now carries three sets (emitted, refused, declared) and `resolve` names which of the four cases a lookup fell into, with the line. An enum that declares one variant twice -- `TokenType.And` is the operator `and` at 16 and the Gherkin keyword `And` at 99 in `compiler/ast.t27` -- kept the last of the repeated key and silently answered 99 to both questions; the first now wins and the displaced one is announced. The discriminant counter still advances past it, so `But` stays 100. `__NOT_EMITTED__` becomes a frozen list rather than an object, because an object with two entries for the same declaration is a TS1117 error in the artifact the TypeScript backend exists to make type-check. `generate_reported` returns the count beside the code, and the wasm bridge publishes it as `targets.js.notEmitted` so a catalog can mark a spec partial without regexing the artifact back apart. Measured over the 1414-spec corpus, emitting every backend and loading every artifact: js and ts each fail 335 specs before and 209 after -- exactly the set that never parses at all, which no backend can serve. 1205 of 1205 emitted modules now import cleanly, and `tsc --noEmit --strict` over all of them leaves one error: `neg_invalid_annotation`, a fixture that exists to be wrong. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…it merely found `check_specs_generate` calls a spec broken only when EVERY backend refuses it, so a js/ts change can move it. Fourteen did, and the gate correctly failed until their ledger lines came out. That half is this pull request's work. The same regeneration adds ten lines, and they are NOT. Every one of them is a parse error: specs/account/auth.t27 parse error in fn 'logout' line 127 specs/ml/optimizer/adamw.t27 parse error in fn 'get_effective_betas' specs/port/tools/_prereq.t27 parse error in fn 'skip' line 33 specs/port/tools/builtin_parity_table.t27 module level line 3, KwPub specs/port/tools/check_damage_negatives.t27 parse error in fn 'parse_report' specs/port/tools/published_figures.t27 Expected LBrace line 131 specs/port/tools/wp18_gate_selfconsistent_selftest.t27 module level line 3 specs/tri/collections/maybe.t27 Expected LBrace line 34 specs/tri/graph/graph_bfs.t27 parse error in fn 'init' line 31 specs/tri/utils/config.t27 Expected LBrace line 42 This branch changes codegen_js.rs, codegen_ts.rs and the wasm bridge. It touches nothing that parses. A file that produces no AST produces none here either, so these ten fail identically on master. Why master is green over them: main() prints the `fixed` class and returns 1 before `new` is ever printed, so a run that has repairs to bless never reports its new failures -- and `.github/workflows/emit-bitexact-gate.yml` is `on: pull_request` with a paths filter on `bootstrap/**`, so master is never measured at all. These ten accumulated where nothing was looking. This is the first branch to touch bootstrap/** since they arrived; it is measuring them, not causing them. The remaining three moved lines (portable/relay_observer, ternary/ hybrid_arithmetic, tools/registry) are the same debts with refreshed message text, not new entries. Ledger: 80 -> 76. It only fell. Closes #4528
gHashTag
force-pushed
the
fix/js-ts-value-layer
branch
from
September 21, 2026 12:37
2c33a9b to
7599a94
Compare
Contributor
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
Contributor
PR DashboardGenerated at: 2026-09-21 12:38:44 UTC
Summary
Seal Status
|
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.
Closes #4528
What was wrong
const_valueanswered every bare identifier withjs_name(name), under a comment reading"a reference to a const declared above". The comment was the only thing checking. Three
shapes in the corpus walked through it and produced artifacts that throw before a single
line of them runs: a name the backend had itself refused to emit, a name declared
further down the file (a
constis not hoisted into a usable state), and a primitivetype name used where a value was expected.
The module is syntactically perfect, so
node --checkpasses. Onlyimportreaches these,and it reaches them all at once — one unbound identifier costs the whole module. The Spec
Explorer showed a green backend chip over a file that cannot be loaded.
Three instruments, each catching what the previous could not
node --checkover 1414 artifactsexport const(SyntaxError, kills the module)importof every artifacttsc --noEmit --strictover allStopping at any one of the three would have shipped the next two.
The fix
Boundcarries three sets — emitted, refused, declared — andresolvesays which ofthe four cases a lookup fell into, with the line number, instead of producing a name and
hoping. A name that genuinely comes from another module is still named as such.
compiler/ast.t27hasTokenType.Andat16 (the operator
and) and again at 99 (the Gherkin keywordAnd). An objectliteral keeps the last of a repeated key, so the artifact silently answered 99 to
both questions. The first now wins, the displaced one is announced, and the discriminant
counter still advances past it —
Butstays 100. TypeScript says this out loud asTS1117; JavaScript does not, which is why it is announced in the artifact rather than
left to a type-checker to notice.
__NOT_EMITTED__becomes a frozen list, not an object, because two entries for thesame declaration is legal in a list and TS1117 in an object — an error in exactly the
artifact the TypeScript backend exists to make type-check.
generate_reportedreturns the omission count beside the code, and the wasm bridgepublishes it as
targets.js.notEmitted. A catalog can now mark a spec partial withoutregexing
__NOT_EMITTED__back out of the artifact, which would be a second, weakerimplementation of something the backend already knows exactly. The five compiled backends
get no such field:
nullreads as no such question, where0would read as noomissions.
Measured over the whole corpus, not sampled
All 1414 specs emitted through every backend, every artifact then loaded:
jsfailstsfailstsc --stricterrors across all artifacts209 is exactly the set that produces no AST at all —
c,rustandzigfail the same209, and no backend can serve them. The js/ts-only failing family is zero. The one
remaining type error is
neg_invalid_annotation, a fixture that exists to be wrong.69 specs now carry a non-empty
__NOT_EMITTED__— 244 declarations announced. These arenot whole modules and not broken ones, and a catalog no longer has to call them either.
cargo test --bin t27c: 1736 passed, 0 failed, 2 ignored (was 1735 — the new test isa_variant_declared_twice_keeps_the_first_and_announces_the_second).What this does NOT establish
The 209 specs that never parse are untouched and unexplained here. Which of them are
damaged files, which are legacy dialects and which are real parser gaps is a separate
question, deliberately not answered on the way past.
🤖 Generated with Claude Code