@scriptc/compiler 0.0.9 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +54 -9
  2. package/dist/backend/emission/emit-exprs.js +170 -14
  3. package/dist/backend/emission/emit-exprs.js.map +1 -1
  4. package/dist/backend/emission/emit-walkers.js +29 -2
  5. package/dist/backend/emission/emit-walkers.js.map +1 -1
  6. package/dist/backend/emission/emitter.js +25 -1
  7. package/dist/backend/emission/emitter.js.map +1 -1
  8. package/dist/backend/llvm/dyn.d.ts +1 -0
  9. package/dist/backend/llvm/dyn.js +83 -1
  10. package/dist/backend/llvm/dyn.js.map +1 -1
  11. package/dist/backend/llvm/emitter.js +210 -13
  12. package/dist/backend/llvm/emitter.js.map +1 -1
  13. package/dist/coverage/surface-manifest.js +16 -2
  14. package/dist/coverage/surface-manifest.js.map +1 -1
  15. package/dist/diagnostics/diagnostic.d.ts +41 -14
  16. package/dist/diagnostics/diagnostic.js +79 -27
  17. package/dist/diagnostics/diagnostic.js.map +1 -1
  18. package/dist/diagnostics/render.js +8 -0
  19. package/dist/diagnostics/render.js.map +1 -1
  20. package/dist/frontend/lowering/lib-boundary.js +11 -1
  21. package/dist/frontend/lowering/lib-boundary.js.map +1 -1
  22. package/dist/frontend/lowering/lower-builtins.d.ts +69 -0
  23. package/dist/frontend/lowering/lower-builtins.js +380 -4
  24. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  25. package/dist/frontend/lowering/lower-calls.d.ts +41 -0
  26. package/dist/frontend/lowering/lower-calls.js +559 -11
  27. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  28. package/dist/frontend/lowering/lower-classes.d.ts +7 -0
  29. package/dist/frontend/lowering/lower-classes.js +51 -1
  30. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  31. package/dist/frontend/lowering/lower-containers.d.ts +21 -0
  32. package/dist/frontend/lowering/lower-containers.js +262 -17
  33. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  34. package/dist/frontend/lowering/lower-dgram.js +92 -17
  35. package/dist/frontend/lowering/lower-dgram.js.map +1 -1
  36. package/dist/frontend/lowering/lower-emitter.d.ts +70 -3
  37. package/dist/frontend/lowering/lower-emitter.js +436 -29
  38. package/dist/frontend/lowering/lower-emitter.js.map +1 -1
  39. package/dist/frontend/lowering/lower-exprs.d.ts +80 -5
  40. package/dist/frontend/lowering/lower-exprs.js +651 -23
  41. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  42. package/dist/frontend/lowering/lower-modules.d.ts +8 -5
  43. package/dist/frontend/lowering/lower-modules.js +144 -19
  44. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  45. package/dist/frontend/lowering/lower-namespaces.d.ts +39 -11
  46. package/dist/frontend/lowering/lower-namespaces.js +166 -24
  47. package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
  48. package/dist/frontend/lowering/lower-server.js +211 -4
  49. package/dist/frontend/lowering/lower-server.js.map +1 -1
  50. package/dist/frontend/lowering/lower-stmts.d.ts +1 -5
  51. package/dist/frontend/lowering/lower-stmts.js +293 -10
  52. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  53. package/dist/frontend/lowering/lower-stream.js +178 -10
  54. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  55. package/dist/frontend/lowering/lowerer.d.ts +53 -1
  56. package/dist/frontend/lowering/lowerer.js +210 -19
  57. package/dist/frontend/lowering/lowerer.js.map +1 -1
  58. package/dist/frontend/lowering/surfaces.d.ts +44 -0
  59. package/dist/frontend/lowering/surfaces.js +234 -3
  60. package/dist/frontend/lowering/surfaces.js.map +1 -1
  61. package/dist/frontend/npm.d.ts +12 -0
  62. package/dist/frontend/npm.js +30 -0
  63. package/dist/frontend/npm.js.map +1 -1
  64. package/dist/frontend/program.d.ts +25 -0
  65. package/dist/frontend/program.js +144 -135
  66. package/dist/frontend/program.js.map +1 -1
  67. package/dist/frontend/shared.d.ts +1 -1
  68. package/dist/frontend/shared.js +1 -1
  69. package/dist/frontend/shared.js.map +1 -1
  70. package/dist/frontend/types.d.ts +13 -0
  71. package/dist/frontend/types.js +84 -7
  72. package/dist/frontend/types.js.map +1 -1
  73. package/dist/index.d.ts +2 -1
  74. package/dist/index.js +157 -12
  75. package/dist/index.js.map +1 -1
  76. package/dist/ir/nodes.d.ts +163 -13
  77. package/dist/ir/nodes.js +65 -6
  78. package/dist/ir/nodes.js.map +1 -1
  79. package/dist/ir/validate.js +64 -5
  80. package/dist/ir/validate.js.map +1 -1
  81. package/dist/library/fence-eval.d.ts +77 -0
  82. package/dist/library/fence-eval.js +395 -0
  83. package/dist/library/fence-eval.js.map +1 -0
  84. package/dist/library/int-infer.d.ts +119 -0
  85. package/dist/library/int-infer.js +1301 -0
  86. package/dist/library/int-infer.js.map +1 -0
  87. package/dist/library/int-infer.test.d.ts +1 -0
  88. package/dist/library/int-infer.test.js +279 -0
  89. package/dist/library/int-infer.test.js.map +1 -0
  90. package/dist/library/profile.d.ts +43 -6
  91. package/dist/library/profile.js +179 -31
  92. package/dist/library/profile.js.map +1 -1
  93. package/dist/library/sidecar.d.ts +23 -0
  94. package/dist/library/sidecar.js +150 -16
  95. package/dist/library/sidecar.js.map +1 -1
  96. package/package.json +2 -2
  97. package/surface-manifest.json +208 -10
@@ -10,6 +10,7 @@ import { FileParts } from "./lower-modules.js";
10
10
  import { ClassInfo, ClassIteratorInfo, GenericClassInfo, findStaticOn } from "./lower-classes.js";
11
11
  import { MixinFnShape } from "./lower-mixins.js";
12
12
  import { ParamShape, FnSig, GenericFnInfo, GenericInstance } from "./lower-calls.js";
13
+ import { type EmitSpecCtx, type EmitSpecRequest } from "./lower-emitter.js";
13
14
  import { FieldTarget } from "./lower-exprs.js";
14
15
  import type { ExpandoMember } from "./lower-expando.js";
15
16
  /** Entry function name. '%' cannot appear in a TS identifier, so a user
@@ -301,6 +302,14 @@ export declare function dynUndefinedExpr(loc: SrcLoc): IrExpr;
301
302
  * an empty code means no code slot. `type` is the replaced expression's
302
303
  * own (never materialized — the global.undefRead pattern). */
303
304
  export declare function nodeThrowExpr(kind: 0 | 1 | 2, code: string, message: string, type: IrType, loc: SrcLoc): IrExpr;
305
+ /** The post-validation fence STRING a validation-ladder Chk libCall
306
+ * throws after its Node-order checks pass: the same SC2020 text the
307
+ * per-statement runtime fence would have thrown (message + "[code at
308
+ * file:line]"), rendered eagerly so the runtime can throw it verbatim
309
+ * (scr_throw_lowering_fence). The diagnostic joins the runtime-fence
310
+ * ledger exactly like a deferred statement fence — nothing silently
311
+ * drops off the coverage report. */
312
+ export declare function ladderFenceExpr(L: Lowerer, surface: string, node: ts.Node, hint?: string): IrExpr;
304
313
  /** The checked-dynamic declaration fallback for unmappable binding types
305
314
  * (see irTypeOf), two gates over one story:
306
315
  *
@@ -357,6 +366,29 @@ export declare class Lowerer {
357
366
  /** Per-symbol result of the never-reassigned file scan
358
367
  * (bindingNeverReassigned — object-literal generic-method receivers). */
359
368
  readonly neverReassignedCache: Map<ts.Symbol, boolean>;
369
+ /** TRAP bindings: declarations whose initializer provably throws before
370
+ * producing a value (its chain roots at an ambient-undefined name —
371
+ * ambientUndefVarRootOf). Module init unwinds at the declaration, so no
372
+ * reference to the binding can ever execute; the statement lowers to the
373
+ * root's throw, no storage exists, and references lower to the same
374
+ * trap shape (never reached — sound whatever the type). */
375
+ readonly trapBindings: Set<ts.Symbol>;
376
+ /** NULLISH bindings of unmappable (generic-signature) types: `const i:
377
+ * I<A & B> = null as any` — the binding provably holds null/undefined
378
+ * forever (every write's RHS is nullish too), so no storage exists and
379
+ * each READ knows the value. Member reads and method calls through one
380
+ * lower to Node's exact TypeError ("Cannot read properties of null
381
+ * (reading 'fn')"); nullish-to-nullish flows lower to nothing. The map
382
+ * answers which unit the binding holds (the TypeError names it). Null
383
+ * entries cache probed non-qualifiers. */
384
+ readonly nullishBindings: Map<ts.Symbol, "undefined" | "null" | null>;
385
+ /** DEAD bindings of unmappable types: never READ anywhere in the
386
+ * program, declared with no initializer or a value-only one (a function
387
+ * literal), every write's RHS side-effect-free. Node materializes the
388
+ * value and drops it — zero observable effect — so the declaration and
389
+ * its writes lower to nothing, and no type fence fires for a value the
390
+ * program never consumes. */
391
+ readonly deadBindings: Set<ts.Symbol>;
360
392
  /** IMPLICIT-ANY function-value bindings (npm-static JS — `const knownBy
361
393
  * = (cmd) => ...`), by their VariableDeclaration: the registered info,
362
394
  * or null for probed non-qualifiers (implicitLocalFnNodeOf). */
@@ -409,6 +441,13 @@ export declare class Lowerer {
409
441
  /** Synthetic array-HOF loop functions (map/filter/forEach desugar),
410
442
  * interned per method + element/callback-result type: key → fn name. */
411
443
  readonly arrHofHelpers: Map<string, string>;
444
+ /** Emit-override specializations (`%C.emit:<event>` — lower-emitter.ts's
445
+ * emit-overrides block): interned names, the drive-loop queue, and the
446
+ * currently-lowering specialization's context (the super-forward
447
+ * interception reads it). */
448
+ readonly emitSpecDone: Set<string>;
449
+ readonly emitSpecQueue: EmitSpecRequest[];
450
+ emitSpecCtx: EmitSpecCtx | null;
412
451
  /** Width-coercion helpers (%rec.width.N / %arr.width.N), interned per
413
452
  * (from, to) shape pair — see widthCoerce. */
414
453
  readonly widthHelpers: Map<string, string>;
@@ -541,6 +580,15 @@ export declare class Lowerer {
541
580
  * `fileName\u0000specifier` (collectDynamicImports fills it during npm
542
581
  * collection; lowerDynamicImportCall reads it per site). */
543
582
  readonly dynImports: Map<string, DynamicImportResolution>;
583
+ /** createRequire-require resolutions of BARE npm specifiers, keyed
584
+ * `fileName\u0000specifier` (collectCreateRequires fills it during npm
585
+ * collection under --dynamic — the require-condition entry key plus its
586
+ * embedded format; lowerCreateRequireCall reads it per site; "" marks a
587
+ * failed resolution already reported at collection). */
588
+ readonly createRequireImports: Map<string, "" | {
589
+ entryKey: string;
590
+ format: "esm" | "cjs" | "json";
591
+ }>;
544
592
  /** Module → the name of its synthesized namespace-BUILDER function
545
593
  * (lowerOwnModuleImport): every `import()` of the same program module
546
594
  * shares one builder. */
@@ -1631,7 +1679,7 @@ export declare class Lowerer {
1631
1679
  stmts: IrStmt[];
1632
1680
  value: IrExpr;
1633
1681
  };
1634
- lowerBindingPattern(pattern: ts.ArrayBindingPattern | ts.ObjectBindingPattern, srcRef: () => IrExpr, srcType: IrType, isLet: boolean, out: IrStmt[]): void;
1682
+ lowerBindingPattern(pattern: ts.ArrayBindingPattern | ts.ObjectBindingPattern, srcRef: () => IrExpr, srcType: IrType, isLet: boolean, out: IrStmt[], dynSpell?: string): void;
1635
1683
  checkBindingElement(el: ts.BindingElement, allowDefault?: boolean): void;
1636
1684
  bindPatternTarget(name: ts.BindingName, value: IrExpr, isLet: boolean, out: IrStmt[]): void;
1637
1685
  lowerVarDeclList(list: ts.VariableDeclarationList): IrStmt | null;
@@ -1799,6 +1847,10 @@ export declare class Lowerer {
1799
1847
  module: string;
1800
1848
  member: string;
1801
1849
  }, loc: SrcLoc): IrExpr | null;
1850
+ lowerFsLadderCall(expr: ts.CallExpression, bi: {
1851
+ module: string;
1852
+ member: string;
1853
+ }, loc: SrcLoc): IrExpr | null;
1802
1854
  lowerChildArgsArg(node: ts.Expression | undefined, loc: SrcLoc): IrExpr;
1803
1855
  lowerSpawnSyncCall(expr: ts.CallExpression, loc: SrcLoc): IrExpr;
1804
1856
  lowerSpawnCall(expr: ts.CallExpression, loc: SrcLoc): IrExpr;
@@ -19,14 +19,15 @@ import { arrayOf, BOOL, canAdaptDynFuncTo, canConvertToDyn, canCrossIslandBounda
19
19
  import { provenanceActive } from "../provenance-registry.js";
20
20
  import { ambientDtsPath, canonicalBuiltinModule, cjsExportAssignmentOf, cjsExportDiscardReason, fallbackDtsPath, isCjsExportTableLiteral, isJsSourceFile, isNodeEsmFile, isNodeTypesPath, locOf, overridesDtsPath, npmStaticDepSf7, requireSpecOf, resolveImport, workspacePackageOfPath, } from "../program.js";
21
21
  import { containsRecord, containsUnion, describeComponentBlocker, describeRecordMemberBlocker, formatIrType, ISLAND_AMBIENT_TYPES, isUnitOnlyTsType, mapType, ShapeRegistry, typeKey, UnionRegistry, withUndefinedArm as withUndefinedArmCanonical, } from "../types.js";
22
- import { boundaryIntoIslandMsg, boundaryOutOfIslandMsg, builtinConstLit, builtinModuleConstOf, builtinFenceHintOf, builtinModuleFnOf, stdlibMemberFence, isStdlibMember, isStdlibSymbol, isStdlibGlobal, stdlibGlobalMember, nodeTypesOnlySymbol } from "./surfaces.js";
22
+ import { boundaryIntoIslandMsg, boundaryOutOfIslandMsg, builtinConstLit, builtinModuleConstOf, builtinModulesArrayLit, builtinFenceHintOf, builtinModuleFnOf, stdlibMemberFence, isStdlibMember, isStdlibSymbol, isStdlibGlobal, stdlibGlobalMember, nodeTypesOnlySymbol } from "./surfaces.js";
23
23
  import { splitFiles, collectProgram, collectNpmImports, collectJsonImports, moduleArtifacts, collectGlobals, declSymbolOf, defaultExportSymbolOf, lowerFileInit, lowerDefaultExport, buildMain, appendDynamicImportModules } from "./lower-modules.js";
24
24
  import { registerBuiltinErrorClasses, registerBuiltinEmitterClass, registerBuiltinStreamClasses, builtinErrorInfoOf, builtinEmitterInfoOf, builtinStreamInfoOf, analyzeClassDecoration, classIteratorDrainCall, classIteratorNextCall, classIteratorOf, classIteratorOpenCall, classIteratorRestDrainCall, classMemberNameOf, classValueRef, collectClassShape, exactClassOfReceiver, collectClassShapeInner, ctorAbiEquals, findMethodOn, findStaticOn, findGenericMethodOn, findGenericStaticOn, genericClassInstanceType, isSubclassOf, inHierarchy, overrideBelow, staticShadowBelow, upcastTo, lowerClassMembers, lowerClassCtor, lowerClassExpression, lowerClassExpressionInfo, lowerClassMethodMember, lowerClassValueProperty, lowerStaticMethod, throwingSetterFn, fieldInitStmts, lowerStaticFieldInits, lowerStaticFieldRead, lowerDerivedCtorBody, superCallStmt, lowerSuperMethodCall, superThisRef, lowerSuperAccessorRead, lowerSuperAccessorWrite, inheritsBuiltinErrorCtor, inheritsBuiltinEmitterCtor, errorMessageArg, lowerNew, accessorCall } from "./lower-classes.js";
25
25
  import { mixinCallClassInfoOf, mixinIntersectionInstanceType } from "./lower-mixins.js";
26
26
  import { bindingNeverReassigned, bodyReadsArguments, isThisParameter, paramShape, paramShapes, checkDefaultParamBodyType, completeArgs, wrappedUndefined, undefinedArgFor, requireExactArityValue, bodyReturnType, declaredReturnType, collectSignature, collectSignatureInner, collectGenericSignature, genericFnOf, lowerGenericCall, lowerGenericFnValue, inferTypeParamBindings, lowerGenericInstance, lowerCall, lowerTimersMemberCall, lowerPromiseMethodCall, lowerFilterNarrowCall, isTopLevelFnSymbol, lowerNestedFunctionDecl, lambdaSignature, lowerLambda, lowerFunction } from "./lower-calls.js";
27
27
  import { lowerArrayMethodCall, lowerBufferStaticCall, lowerBytesMethodCall, lowerBytesNew, lowerMapMethodCall, lowerMapForEachCall, buildMapForEachFn, lowerRecordOvfCaptureHelper, lowerEnvToPairsHelper, lowerSetMethodCall, lowerSetForEachCall, buildSetForEachFn, lowerRegexMethodCall, lowerStringMethodCall } from "./lower-containers.js";
28
28
  import { lowerStreamModuleCall } from "./lower-stream.js";
29
- import { builtinImportOf, lowerBuiltinModuleCall, lowerFsToUnixTimestampCall, lowerChildArgsArg, lowerSpawnSyncCall, lowerSpawnCall, lowerExecSyncCall, recordToEnvPairs, lowerJsonMethodCall, fencedBuiltinImportOf, lowerCryptoComposedCall, lowerUrlMethodCall, lowerSearchParamsMethodCall, lowerStatsMethodCall, lowerChildMethodCall, lowerAtomicsCall, lowerBuiltinExtraProperty, promisifiedExecFileDecl, lowerExecFileAsyncCall, execFileAsyncHelper, lowerStringDecoderMethodCall, strdecHelper, lowerReadlineMethodCall, lowerDcChannelMethodCall, lowerDcChannelProperty, lowerAlsMethodCall, lowerDcTracingChannelMethodCall, lowerDcTracingChannelProperty, lowerJsonProperty, lowerErrorCodeProperty, lowerProcessProperty, isProcessEnv, envValueType, lowerProcessEnvGet, lowerProcessMethodCall, lowerProcessOptionalMethodCall, lowerTimeoutMethodCall, envSnapshotHelper, isConsoleLog, consoleCallMember, lowerNumberStaticCall, lowerNumberStaticProperty, lowerDateCall, lowerTextCodecCall, lowerFsConstantsProperty, lowerHttp2ConstantsProperty, http2ConstantBindingOf, http2ConstantsDestructureDecl, lowerProcessStreamProperty, lowerStringStaticCall, lowerStringLastIndexOfCall, lowerPromiseStaticCall } from "./lower-builtins.js";
29
+ import { lowerEmitOverrideSpec } from "./lower-emitter.js";
30
+ import { builtinImportOf, createRequireBindingDecl, createRequireNamespaceDecl, createRequireSpecOf, stripTypeCasts, lowerBuiltinModuleCall, lowerFsToUnixTimestampCall, lowerFsLadderCall, lowerChildArgsArg, lowerSpawnSyncCall, lowerSpawnCall, lowerExecSyncCall, recordToEnvPairs, lowerJsonMethodCall, fencedBuiltinImportOf, lowerCryptoComposedCall, lowerUrlMethodCall, lowerSearchParamsMethodCall, lowerStatsMethodCall, lowerChildMethodCall, lowerAtomicsCall, lowerBuiltinExtraProperty, promisifiedExecFileDecl, lowerExecFileAsyncCall, execFileAsyncHelper, lowerStringDecoderMethodCall, strdecHelper, lowerReadlineMethodCall, lowerDcChannelMethodCall, lowerDcChannelProperty, lowerAlsMethodCall, lowerDcTracingChannelMethodCall, lowerDcTracingChannelProperty, lowerJsonProperty, lowerErrorCodeProperty, lowerProcessProperty, isProcessEnv, envValueType, lowerProcessEnvGet, lowerProcessMethodCall, lowerProcessOptionalMethodCall, lowerTimeoutMethodCall, envSnapshotHelper, isConsoleLog, consoleCallMember, lowerNumberStaticCall, lowerNumberStaticProperty, lowerDateCall, lowerTextCodecCall, lowerFsConstantsProperty, lowerHttp2ConstantsProperty, http2ConstantBindingOf, http2ConstantsDestructureDecl, lowerProcessStreamProperty, lowerStringStaticCall, lowerStringLastIndexOfCall, lowerPromiseStaticCall } from "./lower-builtins.js";
30
31
  import { isIslandExpr, islandFuncValueFence, islandRegexpOf, jsvalIn, requireDynamicApi, islandGlobalFnOf, lowerDynamicImportCall, lowerFetchCall, lowerIslandMethodCall, lowerMathProperty, npmPackageOf, npmMemberFence, npmPackageOfSymbol } from "./lower-island.js";
31
32
  import { lowerHttpHeadersElement, lowerNetModuleCall, lowerServerMethodCall, lowerServerProperty } from "./lower-server.js";
32
33
  import { lowerDgramDnsModuleCall, lowerDgramMethodCall } from "./lower-dgram.js";
@@ -148,8 +149,24 @@ export function lowerToIr(program, entry, moduleOrder, options = {}) {
148
149
  const dynamic = options.dynamic ?? false;
149
150
  const targetPlatform = options.targetPlatform ?? process.platform;
150
151
  const startupCrash = options.startupCrash ?? null;
152
+ // --dynamic: modules reachable only through dynamic import() of the
153
+ // program's own files join the compiled graph here, ONCE, before any
154
+ // pass constructs (nothing calls their %init at startup — the import()
155
+ // site's namespace builder does, on the engine microtask, Node's
156
+ // evaluation point for them). Inadmissible static cycles inside the
157
+ // added subgraph are minted here and handed to the EMIT pass: the
158
+ // discovery pass's diagnostics are discarded by design, and after this
159
+ // extension of the shared array no later pass re-walks the subgraph.
160
+ const dynamicCycleDiags = [];
161
+ if (dynamic) {
162
+ appendDynamicImportModules(program, moduleOrder, (cycle, reason) => {
163
+ dynamicCycleDiags.push(unsupportedDiag("SC1016", { file: entry.fileName, start: 0, end: 0 }, `circular imports (${cycle}; ${reason})`));
164
+ });
165
+ }
151
166
  const reachable = new Lowerer(program, entry, moduleOrder, dynamic, { targetPlatform }).discover(options.libRoots);
152
167
  const emit = new Lowerer(program, entry, moduleOrder, dynamic, { reachable, targetPlatform, startupCrash });
168
+ for (const d of dynamicCycleDiags)
169
+ emit.pushDiag(d);
153
170
  const result = emit.run();
154
171
  if (options.coverage !== true)
155
172
  return result;
@@ -299,6 +316,26 @@ export function nodeThrowExpr(kind, code, message, type, loc) {
299
316
  loc,
300
317
  };
301
318
  }
319
+ /** The post-validation fence STRING a validation-ladder Chk libCall
320
+ * throws after its Node-order checks pass: the same SC2020 text the
321
+ * per-statement runtime fence would have thrown (message + "[code at
322
+ * file:line]"), rendered eagerly so the runtime can throw it verbatim
323
+ * (scr_throw_lowering_fence). The diagnostic joins the runtime-fence
324
+ * ledger exactly like a deferred statement fence — nothing silently
325
+ * drops off the coverage report. */
326
+ export function ladderFenceExpr(L, surface, node, hint) {
327
+ const loc = locOf(node);
328
+ const d = noLoweringDiag(surface, loc, hint);
329
+ L.runtimeFences.push(d);
330
+ const sf = node.getSourceFile();
331
+ const pos = ts.getLineAndCharacterOfPosition(sf, loc.start);
332
+ return {
333
+ kind: "strLit",
334
+ value: `${d.message} [${d.code} at ${loc.file}:${pos.line + 1}]`,
335
+ type: STRING,
336
+ loc,
337
+ };
338
+ }
302
339
  /** The checked-dynamic declaration fallback for unmappable binding types
303
340
  * (see irTypeOf), two gates over one story:
304
341
  *
@@ -477,6 +514,29 @@ export class Lowerer {
477
514
  /** Per-symbol result of the never-reassigned file scan
478
515
  * (bindingNeverReassigned — object-literal generic-method receivers). */
479
516
  neverReassignedCache = new Map();
517
+ /** TRAP bindings: declarations whose initializer provably throws before
518
+ * producing a value (its chain roots at an ambient-undefined name —
519
+ * ambientUndefVarRootOf). Module init unwinds at the declaration, so no
520
+ * reference to the binding can ever execute; the statement lowers to the
521
+ * root's throw, no storage exists, and references lower to the same
522
+ * trap shape (never reached — sound whatever the type). */
523
+ trapBindings = new Set();
524
+ /** NULLISH bindings of unmappable (generic-signature) types: `const i:
525
+ * I<A & B> = null as any` — the binding provably holds null/undefined
526
+ * forever (every write's RHS is nullish too), so no storage exists and
527
+ * each READ knows the value. Member reads and method calls through one
528
+ * lower to Node's exact TypeError ("Cannot read properties of null
529
+ * (reading 'fn')"); nullish-to-nullish flows lower to nothing. The map
530
+ * answers which unit the binding holds (the TypeError names it). Null
531
+ * entries cache probed non-qualifiers. */
532
+ nullishBindings = new Map();
533
+ /** DEAD bindings of unmappable types: never READ anywhere in the
534
+ * program, declared with no initializer or a value-only one (a function
535
+ * literal), every write's RHS side-effect-free. Node materializes the
536
+ * value and drops it — zero observable effect — so the declaration and
537
+ * its writes lower to nothing, and no type fence fires for a value the
538
+ * program never consumes. */
539
+ deadBindings = new Set();
480
540
  /** IMPLICIT-ANY function-value bindings (npm-static JS — `const knownBy
481
541
  * = (cmd) => ...`), by their VariableDeclaration: the registered info,
482
542
  * or null for probed non-qualifiers (implicitLocalFnNodeOf). */
@@ -540,6 +600,13 @@ export class Lowerer {
540
600
  /** Synthetic array-HOF loop functions (map/filter/forEach desugar),
541
601
  * interned per method + element/callback-result type: key → fn name. */
542
602
  arrHofHelpers = new Map();
603
+ /** Emit-override specializations (`%C.emit:<event>` — lower-emitter.ts's
604
+ * emit-overrides block): interned names, the drive-loop queue, and the
605
+ * currently-lowering specialization's context (the super-forward
606
+ * interception reads it). */
607
+ emitSpecDone = new Set();
608
+ emitSpecQueue = [];
609
+ emitSpecCtx = null;
543
610
  /** Width-coercion helpers (%rec.width.N / %arr.width.N), interned per
544
611
  * (from, to) shape pair — see widthCoerce. */
545
612
  widthHelpers = new Map();
@@ -661,6 +728,12 @@ export class Lowerer {
661
728
  * `fileName\u0000specifier` (collectDynamicImports fills it during npm
662
729
  * collection; lowerDynamicImportCall reads it per site). */
663
730
  dynImports = new Map();
731
+ /** createRequire-require resolutions of BARE npm specifiers, keyed
732
+ * `fileName\u0000specifier` (collectCreateRequires fills it during npm
733
+ * collection under --dynamic — the require-condition entry key plus its
734
+ * embedded format; lowerCreateRequireCall reads it per site; "" marks a
735
+ * failed resolution already reported at collection). */
736
+ createRequireImports = new Map();
664
737
  /** Module → the name of its synthesized namespace-BUILDER function
665
738
  * (lowerOwnModuleImport): every `import()` of the same program module
666
739
  * shares one builder. */
@@ -849,16 +922,12 @@ export class Lowerer {
849
922
  // lowering, long after the constructor completes.
850
923
  isProgramFile: (sf) => this.fileTag.has(sf),
851
924
  };
852
- // --dynamic: modules reachable only through dynamic import() of the
853
- // program's own files join the compiled graph (nothing calls their
854
- // %init at startup — the import() site's namespace builder does, on
855
- // the engine microtask, which is Node's evaluation point for them).
856
- // Mutates the SHARED moduleOrder array; idempotent across passes.
857
- if (dynamic) {
858
- appendDynamicImportModules(program, this.moduleOrder, (cycle) => {
859
- this.pushDiag(unsupportedDiag("SC1016", { file: entry.fileName, start: 0, end: 0 }, `circular imports (${cycle})`));
860
- });
861
- }
925
+ // --dynamic: modules reachable only through dynamic import() joined
926
+ // moduleOrder BEFORE any pass constructed — lowerToIr runs
927
+ // appendDynamicImportModules once on the shared array (a per-pass run
928
+ // here minted cycle refusals into the DISCOVERY pass, whose
929
+ // diagnostics are discarded by design, and the extended order left
930
+ // nothing for the emit pass to re-detect).
862
931
  this.moduleOrder.forEach((sf, i) => {
863
932
  this.fileTag.set(sf, sf === entry ? "" : `%m${i}.`);
864
933
  });
@@ -1367,9 +1436,11 @@ export class Lowerer {
1367
1436
  let ec = 0;
1368
1437
  let gc = 0;
1369
1438
  let gi = 0;
1439
+ let es = 0;
1370
1440
  while (ec < this.exprClasses.length ||
1371
1441
  gc < this.genericClassInstances.length ||
1372
- gi < this.instantiationQueue.length) {
1442
+ gi < this.instantiationQueue.length ||
1443
+ es < this.emitSpecQueue.length) {
1373
1444
  while (ec < this.exprClasses.length) {
1374
1445
  functions.push(...this.lowerClassMembers(this.exprClasses[ec++]));
1375
1446
  }
@@ -1390,6 +1461,20 @@ export class Lowerer {
1390
1461
  throw e;
1391
1462
  }
1392
1463
  }
1464
+ // Emit-override specializations queued by the emit sites above (a
1465
+ // body can queue more — the super-forward chain — and generic
1466
+ // instances of its own; the joint fixpoint covers both).
1467
+ while (es < this.emitSpecQueue.length) {
1468
+ try {
1469
+ const fn = lowerEmitOverrideSpec(this, this.emitSpecQueue[es++]);
1470
+ if (fn)
1471
+ functions.push(fn);
1472
+ }
1473
+ catch (e) {
1474
+ if (!(e instanceof PoisonError))
1475
+ throw e;
1476
+ }
1477
+ }
1393
1478
  }
1394
1479
  }
1395
1480
  // Lambdas lifted while lowering any of the above (plus synthetic
@@ -1707,9 +1792,11 @@ export class Lowerer {
1707
1792
  // the joint fixpoint).
1708
1793
  let instLowered = 0;
1709
1794
  let clsInstLowered = 0;
1795
+ let specLowered = 0;
1710
1796
  const drainInstances = () => {
1711
1797
  while (instLowered < this.instantiationQueue.length ||
1712
- clsInstLowered < this.genericClassInstances.length) {
1798
+ clsInstLowered < this.genericClassInstances.length ||
1799
+ specLowered < this.emitSpecQueue.length) {
1713
1800
  while (instLowered < this.instantiationQueue.length) {
1714
1801
  const { info, inst } = this.instantiationQueue[instLowered++];
1715
1802
  // Body-level poisons skip the instance here too (the emit pass
@@ -1726,6 +1813,18 @@ export class Lowerer {
1726
1813
  while (clsInstLowered < this.genericClassInstances.length) {
1727
1814
  this.lowerClassMembers(this.genericClassInstances[clsInstLowered++]);
1728
1815
  }
1816
+ // Emit-override specialization bodies fire edges of their own
1817
+ // (the super-forward chain, closures, generic calls) — lower them
1818
+ // for discovery exactly like generic instances.
1819
+ while (specLowered < this.emitSpecQueue.length) {
1820
+ try {
1821
+ lowerEmitOverrideSpec(this, this.emitSpecQueue[specLowered++]);
1822
+ }
1823
+ catch (e) {
1824
+ if (!(e instanceof PoisonError))
1825
+ throw e;
1826
+ }
1827
+ }
1729
1828
  }
1730
1829
  };
1731
1830
  parts.forEach((fp) => {
@@ -2361,6 +2460,21 @@ export class Lowerer {
2361
2460
  return expr;
2362
2461
  }
2363
2462
  if (expr.type.kind === "jsval" && expected.kind !== "jsval") {
2463
+ // The jsval→DOM crossing (the world unification's engine-handle
2464
+ // kind): an 'any'-typed engine value flowing into an 'unknown'/
2465
+ // 'object'/JS-residue slot wraps BY REFERENCE as the DOM's island
2466
+ // kind — engine scalars normalize to native DOM kinds at wrap time,
2467
+ // typeof/truthiness/String()/=== route to the engine, un-armed DOM
2468
+ // walks fence loudly, and the value unwraps back identity-preserved
2469
+ // (scr_jsval_from_dyn). Monotone under evolution/widening: a value
2470
+ // wraps once at its first dyn edge and stays valid through every
2471
+ // subsequent dyn slot; narrowing never changes representation.
2472
+ // This wrap RETIRES the silent-wrong-answer fence-closure box for
2473
+ // jsval members of DOM object literals (lowerDynObjectLiteral's
2474
+ // coercion lands here first).
2475
+ if (expected.kind === "dyn") {
2476
+ return { kind: "dynFromJsval", value: expr, type: DYN, loc: expr.loc };
2477
+ }
2364
2478
  // The exit set: everything round-trippable, plus bare undefined-armed
2365
2479
  // unions of JSON-safe data arms (the engine's undefined takes the
2366
2480
  // undefined arm before the JSON detour) — canExitIslandToType.
@@ -5161,6 +5275,11 @@ export class Lowerer {
5161
5275
  if (value.kind === "unitLit") {
5162
5276
  return { kind: "dynFrom", value, type: DYN, loc: value.loc };
5163
5277
  }
5278
+ // An ISLAND ('any') value: the by-reference jsval→DOM wrap — the same
5279
+ // edge coerceToExpected converts (dyn slots accept engine values).
5280
+ if (value.type.kind === "jsval") {
5281
+ return { kind: "dynFromJsval", value, type: DYN, loc: value.loc };
5282
+ }
5164
5283
  if (!this.dynConvertible(value.type)) {
5165
5284
  this.unsupported("SC1100", node, `storing '${this.fmt(value.type)}' values under an 'unknown'-valued index signature (only numbers, strings, booleans, and JSON-safe records/arrays/unions convert)`);
5166
5285
  }
@@ -6116,7 +6235,7 @@ export class Lowerer {
6116
6235
  lowerDestructuringAssignParts(target, rhs, loc) {
6117
6236
  return lowerDestructuringAssignParts(this, target, rhs, loc);
6118
6237
  }
6119
- lowerBindingPattern(pattern, srcRef, srcType, isLet, out) {
6238
+ lowerBindingPattern(pattern, srcRef, srcType, isLet, out, dynSpell) {
6120
6239
  // An ISLAND source (`const { readFileSync } = await import("fs")` —
6121
6240
  // a namespace handle, or any 'any'-typed object): each bound name is
6122
6241
  // an engine property read, mirroring the island property-read rule —
@@ -6180,7 +6299,7 @@ export class Lowerer {
6180
6299
  }
6181
6300
  return;
6182
6301
  }
6183
- return lowerBindingPattern(this, pattern, srcRef, srcType, isLet, out);
6302
+ return lowerBindingPattern(this, pattern, srcRef, srcType, isLet, out, dynSpell);
6184
6303
  }
6185
6304
  checkBindingElement(el, allowDefault = false) {
6186
6305
  return checkBindingElement(this, el, allowDefault);
@@ -6248,7 +6367,12 @@ export class Lowerer {
6248
6367
  // out-of-block read would split the variable in two) — vars take the
6249
6368
  // standard path and its own fences.
6250
6369
  (ts.getCombinedNodeFlags(decl) & ts.NodeFlags.BlockScoped) !== 0 &&
6251
- islandCandidate(decl.initializer)) {
6370
+ islandCandidate(decl.initializer) &&
6371
+ // createRequire's plumbing decls are COMPILE-TIME erasures (the
6372
+ // require binding and its builtin-namespace bindings) — never
6373
+ // island values; the standard path's skips own them.
6374
+ !createRequireBindingDecl(this, decl.name, decl.initializer) &&
6375
+ !createRequireNamespaceDecl(this, decl.name, decl.initializer)) {
6252
6376
  const mapped = this.mapTypeOf(this.typeOf(decl.name));
6253
6377
  const handleOnly = mapped === null ||
6254
6378
  (mapped.kind !== "jsval" &&
@@ -6261,6 +6385,16 @@ export class Lowerer {
6261
6385
  const local = this.declareLocal(decl.name, decl.name.text, JSVAL, isLet);
6262
6386
  return { kind: "varDecl", localId: local.id, init, loc: locOf(decl) };
6263
6387
  }
6388
+ // The CHECKED-DYNAMIC twin of the handle rescue (the runtime-world
6389
+ // local rule): an unmappable declared type over a dyn initializer
6390
+ // (`const first = plugins[0]` — the checker spells 'string |
6391
+ // object' while the read is a DOM keyed read) keeps the binding
6392
+ // dyn; typed use sites ride validated extractions and the routed
6393
+ // engine ops, exactly the JSON.parse-binding story.
6394
+ if (mapped === null && init.type.kind === "dyn") {
6395
+ const local = this.declareLocal(decl.name, decl.name.text, DYN, isLet);
6396
+ return { kind: "varDecl", localId: local.id, init, loc: locOf(decl) };
6397
+ }
6264
6398
  if (mapped === null)
6265
6399
  this.badType(decl.name, this.typeOf(decl.name));
6266
6400
  // A mappable declared type with a non-island initializer: the
@@ -6629,10 +6763,42 @@ export class Lowerer {
6629
6763
  if (!decl)
6630
6764
  return null;
6631
6765
  // The CommonJS twin: `const fs = require("fs")` binds the same
6632
- // namespace surface as `import * as fs from "node:fs"`.
6766
+ // namespace surface as `import * as fs from "node:fs"` — and the
6767
+ // createRequire spelling (`const fs = require("node:fs")` through a
6768
+ // createRequire binding, the fallback-typed cast idiom stripped)
6769
+ // binds it too.
6633
6770
  if (ts.isVariableDeclaration(decl) && ts.isIdentifier(decl.name) && decl.initializer) {
6634
6771
  const spec = requireSpecOf(decl.initializer);
6635
- return spec !== null ? canonicalBuiltinModule(spec) : null;
6772
+ if (spec !== null)
6773
+ return canonicalBuiltinModule(spec);
6774
+ const init = stripTypeCasts(decl.initializer);
6775
+ if (ts.isCallExpression(init)) {
6776
+ const cr = createRequireSpecOf(this, init);
6777
+ if (cr !== null && cr.spec !== null)
6778
+ return canonicalBuiltinModule(cr.spec);
6779
+ }
6780
+ return null;
6781
+ }
6782
+ // A DESTRUCTURED sub-namespace binding — `const { promises } =
6783
+ // fs` / `= require('fs')`: the member is itself a supported module
6784
+ // ("fs/promises"), so the binding carries that module's namespace
6785
+ // surface. canonicalBuiltinModule gates the composition (an
6786
+ // ordinary destructured FUNCTION binding composes to an unknown
6787
+ // name and answers null — builtinImportOf owns those).
6788
+ if (ts.isBindingElement(decl) && ts.isObjectBindingPattern(decl.parent) &&
6789
+ ts.isVariableDeclaration(decl.parent.parent) && decl.parent.parent.initializer !== undefined &&
6790
+ decl.propertyName === undefined && decl.initializer === undefined) {
6791
+ const name = decl.name;
6792
+ if (name === undefined || !ts.isIdentifier(name))
6793
+ return null;
6794
+ const init = decl.parent.parent.initializer;
6795
+ const spec = requireSpecOf(init);
6796
+ const outer = spec !== null
6797
+ ? canonicalBuiltinModule(spec)
6798
+ : ts.isIdentifier(init) ? this.builtinNamespaceModuleOf(init) : null;
6799
+ if (outer !== null)
6800
+ return canonicalBuiltinModule(`${outer}/${name.text}`);
6801
+ return null;
6636
6802
  }
6637
6803
  }
6638
6804
  // The INLINE CommonJS spelling: `require("cluster").isPrimary` — the
@@ -6644,6 +6810,17 @@ export class Lowerer {
6644
6810
  if (spec !== null)
6645
6811
  return canonicalBuiltinModule(spec);
6646
6812
  }
6813
+ // The createRequire spelling of the same inline form:
6814
+ // `require("node:path").join(...)` through a createRequire binding
6815
+ // (the fallback-typed cast idiom strips: `(require("x") as T).m`).
6816
+ {
6817
+ const inner = stripTypeCasts(expr);
6818
+ if (ts.isCallExpression(inner)) {
6819
+ const cr = createRequireSpecOf(this, inner);
6820
+ if (cr !== null && cr.spec !== null)
6821
+ return canonicalBuiltinModule(cr.spec);
6822
+ }
6823
+ }
6647
6824
  if (ts.isIdentifier(expr)) {
6648
6825
  const symbol = this.checker.getSymbolAtLocation(expr);
6649
6826
  const decl = symbol ? this.checker.declarationsOf(symbol)[0] : undefined;
@@ -6746,6 +6923,12 @@ export class Lowerer {
6746
6923
  const fsTs = this.lowerFsToUnixTimestampCall(call, bi, locOf(access));
6747
6924
  if (fsTs)
6748
6925
  return fsTs;
6926
+ // The fs validation-ladder spoke (checked-dynamic lane): misuse of
6927
+ // implemented-namespace members throws Node's typed errors instead
6928
+ // of meeting the table fence.
6929
+ const fsLadder = this.lowerFsLadderCall(call, bi, locOf(access));
6930
+ if (fsLadder)
6931
+ return fsLadder;
6749
6932
  const builtinFn = builtinModuleFnOf(this, bi.module, bi.member);
6750
6933
  if (!builtinFn) {
6751
6934
  this.noLowering(`${bi.module}.${bi.member}`, call, builtinFenceHintOf(bi.module, bi.member), this.checker.getSymbolAtLocation(access.name));
@@ -6784,6 +6967,11 @@ export class Lowerer {
6784
6967
  const c = builtinModuleConstOf(this, bi.module, bi.member);
6785
6968
  if (c !== undefined)
6786
6969
  return builtinConstLit(c, loc);
6970
+ // module.builtinModules through a namespace binding — the baked
6971
+ // Node v24 list, a fresh string[] per read.
6972
+ if (bi.module === "module" && bi.member === "builtinModules") {
6973
+ return builtinModulesArrayLit(loc);
6974
+ }
6787
6975
  if (bi.member === "constants" && bi.module === "fs") {
6788
6976
  // A bare `fs.constants` read (not one of the baked bits above).
6789
6977
  this.noLowering(`fs.constants`, expr, "F_OK, R_OK, W_OK, and X_OK are the lowered constants");
@@ -6799,6 +6987,9 @@ export class Lowerer {
6799
6987
  lowerFsToUnixTimestampCall(expr, bi, loc) {
6800
6988
  return lowerFsToUnixTimestampCall(this, expr, bi, loc);
6801
6989
  }
6990
+ lowerFsLadderCall(expr, bi, loc) {
6991
+ return lowerFsLadderCall(this, expr, bi, loc);
6992
+ }
6802
6993
  lowerChildArgsArg(node, loc) {
6803
6994
  return lowerChildArgsArg(this, node, loc);
6804
6995
  }