@scriptc/compiler 0.2.1 → 0.2.2

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 (193) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +59 -4
  2. package/dist/backend/llvm/dyn.d.ts +3 -0
  3. package/dist/backend/llvm/dyn.js +84 -12
  4. package/dist/backend/llvm/dyn.js.map +1 -1
  5. package/dist/backend/llvm/emitter.d.ts +4 -1
  6. package/dist/backend/llvm/emitter.js +20 -5
  7. package/dist/backend/llvm/emitter.js.map +1 -1
  8. package/dist/backend/llvm/emitter.test.js +9 -1
  9. package/dist/backend/llvm/emitter.test.js.map +1 -1
  10. package/dist/backend/llvm/expr-containers.js +5 -0
  11. package/dist/backend/llvm/expr-containers.js.map +1 -1
  12. package/dist/backend/llvm/expr-dynamic.js +30 -5
  13. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  14. package/dist/backend/llvm/expr-stream-bridges.js +70 -9
  15. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  16. package/dist/backend/llvm/expr-stream-callbacks.d.ts +2 -2
  17. package/dist/backend/llvm/expr-stream-callbacks.js +7 -57
  18. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
  19. package/dist/backend/llvm/lib-dispatch.js +41 -3
  20. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  21. package/dist/backend/llvm/lib-filesystem.js +12 -9
  22. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  23. package/dist/backend/llvm/lib-shared.js +35 -1
  24. package/dist/backend/llvm/lib-shared.js.map +1 -1
  25. package/dist/backend/may-throw.js +4 -0
  26. package/dist/backend/may-throw.js.map +1 -1
  27. package/dist/backend/native-codegen.d.ts +1 -1
  28. package/dist/backend/native-codegen.js +4 -3
  29. package/dist/backend/native-codegen.js.map +1 -1
  30. package/dist/backend/native-codegen.test.js +11 -0
  31. package/dist/backend/native-codegen.test.js.map +1 -1
  32. package/dist/backend/target-diagnostics.d.ts +5 -0
  33. package/dist/backend/target-diagnostics.js +72 -1
  34. package/dist/backend/target-diagnostics.js.map +1 -1
  35. package/dist/backend/target-diagnostics.test.d.ts +1 -0
  36. package/dist/backend/target-diagnostics.test.js +68 -0
  37. package/dist/backend/target-diagnostics.test.js.map +1 -0
  38. package/dist/coverage/surface-manifest.js +5 -3
  39. package/dist/coverage/surface-manifest.js.map +1 -1
  40. package/dist/executable/executable-cache.d.ts +7 -3
  41. package/dist/executable/executable-cache.js +47 -11
  42. package/dist/executable/executable-cache.js.map +1 -1
  43. package/dist/executable/executable-cache.test.js +109 -2
  44. package/dist/executable/executable-cache.test.js.map +1 -1
  45. package/dist/executable/prepare.js +2 -1
  46. package/dist/executable/prepare.js.map +1 -1
  47. package/dist/frontend/builtin-modules.d.ts +1 -1
  48. package/dist/frontend/builtin-modules.js +1 -1
  49. package/dist/frontend/builtin-modules.js.map +1 -1
  50. package/dist/frontend/function-completion.d.ts +6 -0
  51. package/dist/frontend/function-completion.js +50 -0
  52. package/dist/frontend/function-completion.js.map +1 -0
  53. package/dist/frontend/lowering/abstract-equality.js +5 -1
  54. package/dist/frontend/lowering/abstract-equality.js.map +1 -1
  55. package/dist/frontend/lowering/checked-iterable-spread.d.ts +4 -0
  56. package/dist/frontend/lowering/checked-iterable-spread.js +30 -0
  57. package/dist/frontend/lowering/checked-iterable-spread.js.map +1 -0
  58. package/dist/frontend/lowering/checked-promise-all.d.ts +5 -0
  59. package/dist/frontend/lowering/checked-promise-all.js +31 -0
  60. package/dist/frontend/lowering/checked-promise-all.js.map +1 -0
  61. package/dist/frontend/lowering/class-callbacks.d.ts +1 -1
  62. package/dist/frontend/lowering/class-callbacks.js +7 -6
  63. package/dist/frontend/lowering/class-callbacks.js.map +1 -1
  64. package/dist/frontend/lowering/class-construction.d.ts +2 -0
  65. package/dist/frontend/lowering/class-construction.js +34 -5
  66. package/dist/frontend/lowering/class-construction.js.map +1 -1
  67. package/dist/frontend/lowering/class-descriptors.d.ts +1 -1
  68. package/dist/frontend/lowering/class-descriptors.js +12 -5
  69. package/dist/frontend/lowering/class-descriptors.js.map +1 -1
  70. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +25 -0
  71. package/dist/frontend/lowering/class-dynamic-dispatch.js +597 -78
  72. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  73. package/dist/frontend/lowering/class-dynamic-dispatch.test.js +64 -2
  74. package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
  75. package/dist/frontend/lowering/class-instance-constructor.d.ts +1 -1
  76. package/dist/frontend/lowering/class-instance-constructor.js +11 -41
  77. package/dist/frontend/lowering/class-instance-constructor.js.map +1 -1
  78. package/dist/frontend/lowering/class-method-values.d.ts +16 -0
  79. package/dist/frontend/lowering/class-method-values.js +60 -29
  80. package/dist/frontend/lowering/class-method-values.js.map +1 -1
  81. package/dist/frontend/lowering/class-prototypes.d.ts +5 -1
  82. package/dist/frontend/lowering/class-prototypes.js +69 -10
  83. package/dist/frontend/lowering/class-prototypes.js.map +1 -1
  84. package/dist/frontend/lowering/class-runtime-statics.d.ts +4 -4
  85. package/dist/frontend/lowering/class-runtime-statics.js +26 -8
  86. package/dist/frontend/lowering/class-runtime-statics.js.map +1 -1
  87. package/dist/frontend/lowering/class-static-data.d.ts +1 -0
  88. package/dist/frontend/lowering/class-static-data.js +4 -2
  89. package/dist/frontend/lowering/class-static-data.js.map +1 -1
  90. package/dist/frontend/lowering/containers/bytes.js +17 -4
  91. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  92. package/dist/frontend/lowering/containers/string-and-regexp.js +6 -1
  93. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  94. package/dist/frontend/lowering/deferred-module-initializers.d.ts +13 -0
  95. package/dist/frontend/lowering/deferred-module-initializers.js +410 -0
  96. package/dist/frontend/lowering/deferred-module-initializers.js.map +1 -0
  97. package/dist/frontend/lowering/deferred-module-initializers.test.d.ts +1 -0
  98. package/dist/frontend/lowering/deferred-module-initializers.test.js +92 -0
  99. package/dist/frontend/lowering/deferred-module-initializers.test.js.map +1 -0
  100. package/dist/frontend/lowering/expressions/object-literals.js +31 -1
  101. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  102. package/dist/frontend/lowering/expressions/optional-chains.js +3 -3
  103. package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
  104. package/dist/frontend/lowering/lower-builtins.d.ts +4 -9
  105. package/dist/frontend/lowering/lower-builtins.js +291 -51
  106. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  107. package/dist/frontend/lowering/lower-calls.js +283 -73
  108. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  109. package/dist/frontend/lowering/lower-classes.d.ts +5 -0
  110. package/dist/frontend/lowering/lower-classes.js +439 -25
  111. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  112. package/dist/frontend/lowering/lower-containers.d.ts +1 -1
  113. package/dist/frontend/lowering/lower-containers.js +39 -17
  114. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  115. package/dist/frontend/lowering/lower-exprs.d.ts +10 -6
  116. package/dist/frontend/lowering/lower-exprs.js +294 -129
  117. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  118. package/dist/frontend/lowering/lower-generators.js +5 -1
  119. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  120. package/dist/frontend/lowering/lower-inspect.js +15 -1
  121. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  122. package/dist/frontend/lowering/lower-island.js +4 -0
  123. package/dist/frontend/lowering/lower-island.js.map +1 -1
  124. package/dist/frontend/lowering/lower-island.test.d.ts +1 -0
  125. package/dist/frontend/lowering/lower-island.test.js +51 -0
  126. package/dist/frontend/lowering/lower-island.test.js.map +1 -0
  127. package/dist/frontend/lowering/lower-modules.d.ts +1 -3
  128. package/dist/frontend/lowering/lower-modules.js +186 -82
  129. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  130. package/dist/frontend/lowering/lower-modules.test.js +69 -1
  131. package/dist/frontend/lowering/lower-modules.test.js.map +1 -1
  132. package/dist/frontend/lowering/lower-stmts.js +100 -35
  133. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  134. package/dist/frontend/lowering/lower-stmts.test.d.ts +1 -0
  135. package/dist/frontend/lowering/lower-stmts.test.js +77 -0
  136. package/dist/frontend/lowering/lower-stmts.test.js.map +1 -0
  137. package/dist/frontend/lowering/lower-stream.js +2 -0
  138. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  139. package/dist/frontend/lowering/lower-url.d.ts +2 -1
  140. package/dist/frontend/lowering/lower-url.js +32 -9
  141. package/dist/frontend/lowering/lower-url.js.map +1 -1
  142. package/dist/frontend/lowering/lowerer.d.ts +26 -9
  143. package/dist/frontend/lowering/lowerer.js +218 -27
  144. package/dist/frontend/lowering/lowerer.js.map +1 -1
  145. package/dist/frontend/lowering/lowerer.test.js +38 -0
  146. package/dist/frontend/lowering/lowerer.test.js.map +1 -1
  147. package/dist/frontend/lowering/module-namespace-elements.d.ts +7 -0
  148. package/dist/frontend/lowering/module-namespace-elements.js +54 -0
  149. package/dist/frontend/lowering/module-namespace-elements.js.map +1 -0
  150. package/dist/frontend/lowering/object-factory-new.d.ts +4 -3
  151. package/dist/frontend/lowering/object-factory-new.js +27 -14
  152. package/dist/frontend/lowering/object-factory-new.js.map +1 -1
  153. package/dist/frontend/lowering/surfaces.d.ts +1 -0
  154. package/dist/frontend/lowering/surfaces.js +24 -12
  155. package/dist/frontend/lowering/surfaces.js.map +1 -1
  156. package/dist/frontend/lowering/text-decoder-encoding.js +3 -0
  157. package/dist/frontend/lowering/text-decoder-encoding.js.map +1 -1
  158. package/dist/frontend/lowering/text-decoder-encoding.test.js +2 -1
  159. package/dist/frontend/lowering/text-decoder-encoding.test.js.map +1 -1
  160. package/dist/frontend/program.js +4 -2
  161. package/dist/frontend/program.js.map +1 -1
  162. package/dist/frontend/type-mapper.js +83 -14
  163. package/dist/frontend/type-mapper.js.map +1 -1
  164. package/dist/frontend/union-discriminants.js +22 -7
  165. package/dist/frontend/union-discriminants.js.map +1 -1
  166. package/dist/index.js +16 -10
  167. package/dist/index.js.map +1 -1
  168. package/dist/ir/ir.d.ts +27 -13
  169. package/dist/ir/ir.js +26 -2
  170. package/dist/ir/ir.js.map +1 -1
  171. package/dist/ir/serialize.js +21 -1
  172. package/dist/ir/serialize.js.map +1 -1
  173. package/dist/ir/serialize.test.js +21 -0
  174. package/dist/ir/serialize.test.js.map +1 -1
  175. package/dist/ir/traverse.d.ts +0 -3
  176. package/dist/ir/traverse.js +33 -20
  177. package/dist/ir/traverse.js.map +1 -1
  178. package/dist/ir/validate.js +56 -5
  179. package/dist/ir/validate.js.map +1 -1
  180. package/dist/ir/validate.test.js +17 -1
  181. package/dist/ir/validate.test.js.map +1 -1
  182. package/dist/library/compiler-self-identity.js +1 -1
  183. package/dist/library/compiler-self-identity.test.js +2 -2
  184. package/dist/library/compiler-self-identity.test.js.map +1 -1
  185. package/dist/library/int-infer.d.ts +2 -2
  186. package/dist/library/int-infer.js +10 -7
  187. package/dist/library/int-infer.js.map +1 -1
  188. package/dist/library/int-infer.test.js +44 -0
  189. package/dist/library/int-infer.test.js.map +1 -1
  190. package/dist/library/prepare.js +2 -1
  191. package/dist/library/prepare.js.map +1 -1
  192. package/package.json +20 -20
  193. package/surface-manifest.json +115 -13
@@ -4,6 +4,7 @@ export type { WidthLift } from "./width-lift.js";
4
4
  import { type FnCtx } from "./function-context.js";
5
5
  export { newFnCtx, type FnCtx } from "./function-context.js";
6
6
  import type { FrontendServices } from "../services.js";
7
+ import { DeferredModuleInitializers } from "./deferred-module-initializers.js";
7
8
  import type { ClassSymbolKey } from "./symbol-fields.js";
8
9
  import type { HttpClientFnBinding } from "./lower-server.js";
9
10
  import * as ts from "../ts7/adapter.js";
@@ -324,15 +325,13 @@ export declare function ladderFenceExpr(lowerer: Lowerer, surface: string, node:
324
325
  *
325
326
  * Null for void (no value exists to represent). */
326
327
  export declare function dynFallbackType(lowerer: Lowerer, node: ts.Node, t: ts.Type): IrType | null;
327
- /** The best-effort JS `Function.prototype.name` of an expression flowing
328
- * into a dyn slot (the boxed function kind's inspect/error name):
329
- * identifier and property reads answer the referenced NAME (a
330
- * REFERENCE-SITE approximation of JS's creation-site naming — an aliased
331
- * binding reports the alias; SEMANTICS.md), named function expressions
328
+ /** The JS `Function.prototype.name` of an expression flowing into a dyn
329
+ * slot. Immutable identifier aliases retain their creation-site name; property
330
+ * reads answer the referenced name. Named function expressions
332
331
  * their own name, anonymous function/arrow expressions their
333
332
  * NamedEvaluation home (a variable initializer or property assignment).
334
333
  * Null when nothing names the value (the box stays anonymous). */
335
- export declare function jsFuncNameOf(node: ts.Node): string | null;
334
+ export declare function jsFuncNameOf(node: ts.Node, lowerer?: Lowerer): string | null;
336
335
  export declare class Lowerer {
337
336
  readonly program: ts.Program;
338
337
  readonly entry: ts.SourceFile;
@@ -361,6 +360,9 @@ export declare class Lowerer {
361
360
  /** Per-symbol result of the never-reassigned file scan
362
361
  * (bindingNeverReassigned — object-literal generic-method receivers). */
363
362
  readonly neverReassignedCache: Map<ts.Symbol, boolean>;
363
+ /** Syntactic writes indexed once per JS scope. Symbol and RHS type
364
+ * checks remain contextual to each binding probe. */
365
+ readonly jsBindingWritesByOwner: Map<import("../ts7/ast-node.js").AstNode, Map<string, ts.BinaryExpression[]>>;
364
366
  /** TRAP bindings: declarations whose initializer provably throws before
365
367
  * producing a value (its chain roots at an ambient-undefined name —
366
368
  * ambientUndefVarRootOf). Module init unwinds at the declaration, so no
@@ -508,8 +510,8 @@ export declare class Lowerer {
508
510
  } | null;
509
511
  /** Recover the original optional union when a checked single-arm helper
510
512
  * was installed before a strict property consumer could name its member.
511
- * Recovery is limited to array element reads and storage roots marked by
512
- * the optional-read analysis, so ordinary assertions keep their generic
513
+ * Recovery covers member reads and storage roots marked by the
514
+ * optional-read analysis, so ordinary assertions keep their generic
513
515
  * checked-narrow behavior. */
514
516
  runtimeOptionalSourceValue(node: ts.Expression, value: IrExpr): IrExpr | null;
515
517
  /** A strict property or method receiver over an array-derived optional
@@ -594,10 +596,12 @@ export declare class Lowerer {
594
596
  private readonly copyRetagHelpers;
595
597
  private readonly unionLiteralOwners;
596
598
  private readonly strippedUndefinedArms;
599
+ private readonly addedUndefinedArms;
597
600
  private readonly stdlibSymbols;
598
601
  /** Method adapter names are owned by class-method-values. Looking them
599
602
  * up must not scan and retain every unrelated lifted function. */
600
603
  readonly classMethodValueHelpers: Set<string>;
604
+ readonly classMethodValueSelections: Map<string, import("./class-method-values.js").ClassMethodValueSelection>;
601
605
  /** Callee names of every interned coercion helper whose CALL mints a
602
606
  * FRESH closure per evaluation (%fn.width.*, %fn.adapt.*,
603
607
  * %fnval.spawnres.*). Registered at the mint site — NOT recovered by
@@ -705,9 +709,15 @@ export declare class Lowerer {
705
709
  /** Inferred JS methods participating in an override chain keep a vtable
706
710
  * ABI instead of call-site specialization. Filled before class collection. */
707
711
  readonly virtualJsMethods: Set<ts.MethodDeclaration>;
712
+ /** Descendant writes must widen the original JS field before collecting
713
+ * any class layout; base and derived instances share its storage ABI. */
714
+ readonly inheritedJsFieldWrites: Map<ts.ClassDeclaration | ts.ClassExpression, Map<string, ts.ExpressionBase[]>>;
708
715
  /** Largest fixed argument list below a JS method, discovered before any
709
716
  * base vtable signature is collected. Unused checked slots carry undefined. */
710
717
  readonly virtualJsMethodArity: Map<ts.MethodDeclaration, number>;
718
+ readonly checkedVirtualJsMethods: Set<ts.MethodDeclaration>;
719
+ readonly checkedVirtualJsAccessors: Set<ts.GetAccessorDeclaration | ts.SetAccessorDeclaration>;
720
+ readonly checkedVirtualJsValueReturns: Set<ts.MethodDeclaration>;
711
721
  /** The class whose members are lowering — `super` binds lexically to it
712
722
  * (arrows inside methods lower within this window, so they see it too). */
713
723
  currentClass: ClassInfo | null;
@@ -849,6 +859,7 @@ export declare class Lowerer {
849
859
  * a reference to a lowerable body reports its name here — recorded even
850
860
  * when the enclosing statement later poisons. */
851
861
  onEdge: ((name: string) => void) | null;
862
+ deferredModuleInitializers: DeferredModuleInitializers | null;
852
863
  fnStack: FnCtx[];
853
864
  readonly liftedFns: IrFunction[];
854
865
  /** One Error-method helper belongs to this lowering session. Its cached
@@ -884,6 +895,12 @@ export declare class Lowerer {
884
895
  * is assembled directly. The configured reachable set remains null so
885
896
  * demand-driven instance lowering keeps its existing gates. */
886
897
  reachableForArtifacts: ReadonlySet<string> | null;
898
+ /** Constructors retained by the active worklist. A boxed base receiver
899
+ * can contain any retained descendant, but importing its declaration
900
+ * alone does not make every descendant constructible. */
901
+ private constructedClasses;
902
+ private readonly virtualEdges;
903
+ classCanBeConstructed(info: ClassInfo): boolean;
887
904
  /** Coverage remainder mode: the reachability gate inverts (see wantBody)
888
905
  * and no module is built. */
889
906
  readonly remainder: boolean;
@@ -2245,7 +2262,7 @@ export declare class Lowerer {
2245
2262
  lowerDcChannelProperty(access: ts.PropertyAccessExpression): IrExpr | null;
2246
2263
  lowerDcTracingChannelMethodCall(call: ts.CallExpression, access: ts.PropertyAccessExpression): IrExpr | null;
2247
2264
  lowerDcTracingChannelProperty(access: ts.PropertyAccessExpression): IrExpr | null;
2248
- strdecHelper(op: "write" | "end", shapeId: string, loc: SrcLoc): string;
2265
+ strdecHelper(op: "write" | "end" | "endChunk" | "endString" | "writeString", shapeId: string, loc: SrcLoc): string;
2249
2266
  lowerProcessProperty(expr: ts.PropertyAccessExpression): IrExpr | null;
2250
2267
  lowerFsConstantsProperty(expr: ts.PropertyAccessExpression): IrExpr | null;
2251
2268
  lowerBuiltinConstantsProperty(expr: ts.PropertyAccessExpression): IrExpr | null;
@@ -1,5 +1,5 @@
1
1
  import { pathModuleValue } from "./lower-builtin-values.js";
2
- import { everyExprChild, everyStmtChild } from "../../ir/traverse.js";
2
+ import { everyExprChild, everyStmtChild, transformStmtList } from "../../ir/traverse.js";
3
3
  import { RuntimeOptionalLocals } from "./runtime-optional-locals.js";
4
4
  import { sanitizeUnregisteredClassTypes } from "./sanitize-class-types.js";
5
5
  import { UnregisteredClassTypes } from "./unregistered-class-types.js";
@@ -9,7 +9,8 @@ import { bindingInContext, captureContextBinding, declareContextLocal, declareCo
9
9
  export { newFnCtx } from "./function-context.js";
10
10
  import { InternalCompilerError } from "../../errors.js";
11
11
  import { defaultAfterUndefined, lowerStaticallyUndefinedArgument } from "./optional-arguments.js";
12
- import { ClassDynamicDispatch } from "./class-dynamic-dispatch.js";
12
+ import { ClassDynamicDispatch, trackClassFieldCreation } from "./class-dynamic-dispatch.js";
13
+ import { DeferredModuleInitializers } from "./deferred-module-initializers.js";
13
14
  import { finalizeClassMethodValues } from "./class-method-values.js";
14
15
  /* AST + checker → IR.
15
16
  *
@@ -37,7 +38,7 @@ import {} from "../npm.js";
37
38
  import { provenanceActive } from "../provenance-registry.js";
38
39
  import { ambientDtsPath, canonicalBuiltinModule, cjsExportAssignmentOf, cjsExportDiscardReason, fallbackDtsPath, isCjsExportTableLiteral, isCjsJsFile, isJsSourceFile, isNodeEsmFile, isNodeTypesPath, locOf, orderedImportsOf, overridesDtsPath, npmStaticDepSf7, requireSpecOf, resolveImport, workspacePackageOfPath, } from "../program.js";
39
40
  import { containsRecord, containsUnion, describeComponentBlocker, describeRecordMemberBlocker, formatIrType, ISLAND_AMBIENT_TYPES, isUnitOnlyTsType, jsOpenObjectType, mapType, ShapeRegistry, typeKey, UnionRegistry, withUndefinedArm as withUndefinedArmCanonical, } from "../type-mapper.js";
40
- import { boundaryIntoIslandMsg, boundaryOutOfIslandMsg, builtinConstLit, builtinModuleConstOf, builtinModulesArrayLit, builtinFenceHintOf, builtinModuleFnOf, stdlibMemberFence, isStdlibMember, isStdlibSymbol, isStdlibGlobal, stdlibGlobalMember, nodeTypesOnlySymbol } from "./surfaces.js";
41
+ import { boundaryIntoIslandMsg, boundaryOutOfIslandMsg, builtinConstLit, builtinModuleConstOf, builtinModulesArrayLit, builtinFenceHintOf, builtinModuleFnOf, stdlibMemberFence, isStdlibMember, isStdlibSymbol, isStdlibGlobal, stdlibGlobalNameOf, stdlibGlobalMember, nodeTypesOnlySymbol } from "./surfaces.js";
41
42
  import { splitFiles, collectProgram, collectNpmImports, collectJsonImports, moduleArtifacts, collectGlobals, declSymbolOf, defaultExportSymbolOf, lowerFileInit, lowerDefaultExport, buildMain, appendDynamicImportModules, appendForkModules } from "./lower-modules.js";
42
43
  import { prepareCjsModuleGraph } from "./lower-node-module.js";
43
44
  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, errorConstructorArgs, lowerNew, accessorCall } from "./lower-classes.js";
@@ -58,7 +59,7 @@ import { lowerNodeTestModuleCall, lowerTestDirectCall, lowerTestMethodCall, lowe
58
59
  import { lowerAssertModuleCall, lowerAssertDirectCall } from "./lower-assert.js";
59
60
  import { lowerUtilModuleCall } from "./lower-inspect.js";
60
61
  import { lowerComptime, comptimeBakeable, rejectComptimeCaptures, comptimeValueToIr } from "./lower-comptime.js";
61
- import { lowerStmts, noteBlockedBindings, isBlockedBinding, lowerScopedBlock, predeclareForwardCapture, predeclareForwardFnDecl, predeclareForwardVar, lowerStmt, lowerVarStatement, lowerDestructuringDecl, lowerDestructuringAssignParts, lowerBindingPattern, lowerJsvalBindingPattern, checkBindingElement, bindPatternTarget, isParseArgsDynCheckerType, lowerVarDeclList, lowerVarDecl, lowerSwitch, lowerTry, lowerExprStatement, lowerForOf, lowerForStatement } from "./lower-stmts.js";
62
+ import { lowerStmts, hasJsTypeAnnotation, noteBlockedBindings, isBlockedBinding, lowerScopedBlock, predeclareForwardCapture, predeclareForwardFnDecl, predeclareForwardVar, lowerStmt, lowerVarStatement, lowerDestructuringDecl, lowerDestructuringAssignParts, lowerBindingPattern, lowerJsvalBindingPattern, checkBindingElement, bindPatternTarget, isParseArgsDynCheckerType, lowerVarDeclList, lowerVarDecl, lowerSwitch, lowerTry, lowerExprStatement, lowerForOf, lowerForStatement } from "./lower-stmts.js";
62
63
  import { lowerExpr, maybeNarrow, lowerUnitComparison, lowerNullishCoalesce, lowerCondition, ensureBool, requireTruthyUnion, eqComparableUnion, lowerIntrinsicProperty, lowerArrayLiteral, lowerElementAccess, lowerElementWrite, lowerRecordKeyRead, ensureString, lowerTemplate, lowerAsExpression, lowerPrefixUnary, lowerBinary, lowerCaughtTypeofTest, caughtRead, caughtLocalOf, caughtToString, lowerInstanceOf, lowerRegexLiteral, lowerFieldRead, lowerUnionProperty, fieldTarget, fieldGetExpr, fieldSetStmt, lowerFieldCompound, uniqueSymbolKeyOf } from "./lower-exprs.js";
63
64
  import { finishOptionalChain, isOptionalChainTail, lowerOptionalChain } from "./expressions/optional-chains.js";
64
65
  import { foldedStringKeyOf, lowerDynObjectLiteral, lowerObjectLiteral, lowerShorthandValue, rejectThisInObjectMethod } from "./expressions/object-literals.js";
@@ -751,18 +752,34 @@ function anyPiecedFuncType(lowerer, node, t) {
751
752
  return null;
752
753
  return { kind: "func", params, ret };
753
754
  }
754
- /** The best-effort JS `Function.prototype.name` of an expression flowing
755
- * into a dyn slot (the boxed function kind's inspect/error name):
756
- * identifier and property reads answer the referenced NAME (a
757
- * REFERENCE-SITE approximation of JS's creation-site naming — an aliased
758
- * binding reports the alias; SEMANTICS.md), named function expressions
755
+ /** The JS `Function.prototype.name` of an expression flowing into a dyn
756
+ * slot. Immutable identifier aliases retain their creation-site name; property
757
+ * reads answer the referenced name. Named function expressions
759
758
  * their own name, anonymous function/arrow expressions their
760
759
  * NamedEvaluation home (a variable initializer or property assignment).
761
760
  * Null when nothing names the value (the box stays anonymous). */
762
- export function jsFuncNameOf(node) {
761
+ export function jsFuncNameOf(node, lowerer) {
763
762
  let n = node;
764
763
  while (ts.isParenthesizedExpression(n))
765
764
  n = n.expression;
765
+ const seen = new Set();
766
+ while (lowerer && ts.isIdentifier(n)) {
767
+ const symbol = lowerer.resolveValueSymbol(n);
768
+ if (!symbol || seen.has(symbol))
769
+ break;
770
+ seen.add(symbol);
771
+ const declaration = lowerer.checker.valueDeclarationOf(symbol);
772
+ if (declaration && ts.isFunctionDeclaration(declaration)) {
773
+ n = declaration;
774
+ break;
775
+ }
776
+ if (!declaration || !ts.isVariableDeclaration(declaration) || !declaration.initializer ||
777
+ (ts.getCombinedNodeFlags(declaration) & ts.NodeFlags.Const) === 0)
778
+ break;
779
+ n = declaration.initializer;
780
+ while (ts.isParenthesizedExpression(n))
781
+ n = n.expression;
782
+ }
766
783
  if (ts.isIdentifier(n))
767
784
  return n.text;
768
785
  if (ts.isPropertyAccessExpression(n))
@@ -811,6 +828,9 @@ export class Lowerer {
811
828
  /** Per-symbol result of the never-reassigned file scan
812
829
  * (bindingNeverReassigned — object-literal generic-method receivers). */
813
830
  neverReassignedCache = new Map();
831
+ /** Syntactic writes indexed once per JS scope. Symbol and RHS type
832
+ * checks remain contextual to each binding probe. */
833
+ jsBindingWritesByOwner = new Map();
814
834
  /** TRAP bindings: declarations whose initializer provably throws before
815
835
  * producing a value (its chain roots at an ambient-undefined name —
816
836
  * ambientUndefVarRootOf). Module init unwinds at the declaration, so no
@@ -1090,7 +1110,7 @@ export class Lowerer {
1090
1110
  // the initializer cannot fall back to a narrowing adapter.
1091
1111
  if (ts.isIdentifier(node) && fallback?.kind === "func") {
1092
1112
  const decl = this.checker.valueDeclarationOf(symbol);
1093
- if (decl && ts.isVariableDeclaration(decl) && decl.initializer) {
1113
+ if (decl && ts.isVariableDeclaration(decl) && !decl.type && !hasJsTypeAnnotation(decl) && decl.initializer) {
1094
1114
  let init = decl.initializer;
1095
1115
  while (ts.isParenthesizedExpression(init))
1096
1116
  init = init.expression;
@@ -1124,14 +1144,14 @@ export class Lowerer {
1124
1144
  }
1125
1145
  /** Recover the original optional union when a checked single-arm helper
1126
1146
  * was installed before a strict property consumer could name its member.
1127
- * Recovery is limited to array element reads and storage roots marked by
1128
- * the optional-read analysis, so ordinary assertions keep their generic
1147
+ * Recovery covers member reads and storage roots marked by the
1148
+ * optional-read analysis, so ordinary assertions keep their generic
1129
1149
  * checked-narrow behavior. */
1130
1150
  runtimeOptionalSourceValue(node, value) {
1131
1151
  let origin = node;
1132
1152
  while (ts.isParenthesizedExpression(origin))
1133
1153
  origin = origin.expression;
1134
- let optionalOrigin = ts.isElementAccessExpression(origin);
1154
+ let optionalOrigin = ts.isElementAccessExpression(origin) || ts.isPropertyAccessExpression(origin);
1135
1155
  if (ts.isIdentifier(origin)) {
1136
1156
  const local = this.resolveLocal(origin);
1137
1157
  const root = local ? this.runtimeOptionalRootOf(local) : null;
@@ -1143,6 +1163,10 @@ export class Lowerer {
1143
1163
  }
1144
1164
  if (!optionalOrigin)
1145
1165
  return null;
1166
+ // A checked JavaScript indexed read can already be boxed. The checker
1167
+ // calls the element present, but that inference is not a runtime guard.
1168
+ if (isJsSourceFile(node.getSourceFile()) && value.kind === "dynCheck" && value.value.type.kind === "dyn")
1169
+ return value.value;
1146
1170
  let source = value;
1147
1171
  if (value.kind === "call" &&
1148
1172
  this.checkedNarrowHelpers.has(value.callee) &&
@@ -1348,10 +1372,12 @@ export class Lowerer {
1348
1372
  copyRetagHelpers = new Map();
1349
1373
  unionLiteralOwners = new Map();
1350
1374
  strippedUndefinedArms = new Map();
1375
+ addedUndefinedArms = new Map();
1351
1376
  stdlibSymbols = new Map();
1352
1377
  /** Method adapter names are owned by class-method-values. Looking them
1353
1378
  * up must not scan and retain every unrelated lifted function. */
1354
1379
  classMethodValueHelpers = new Set();
1380
+ classMethodValueSelections = new Map();
1355
1381
  /** Callee names of every interned coercion helper whose CALL mints a
1356
1382
  * FRESH closure per evaluation (%fn.width.*, %fn.adapt.*,
1357
1383
  * %fnval.spawnres.*). Registered at the mint site — NOT recovered by
@@ -1442,9 +1468,15 @@ export class Lowerer {
1442
1468
  /** Inferred JS methods participating in an override chain keep a vtable
1443
1469
  * ABI instead of call-site specialization. Filled before class collection. */
1444
1470
  virtualJsMethods = new Set();
1471
+ /** Descendant writes must widen the original JS field before collecting
1472
+ * any class layout; base and derived instances share its storage ABI. */
1473
+ inheritedJsFieldWrites = new Map();
1445
1474
  /** Largest fixed argument list below a JS method, discovered before any
1446
1475
  * base vtable signature is collected. Unused checked slots carry undefined. */
1447
1476
  virtualJsMethodArity = new Map();
1477
+ checkedVirtualJsMethods = new Set();
1478
+ checkedVirtualJsAccessors = new Set();
1479
+ checkedVirtualJsValueReturns = new Set();
1448
1480
  /** The class whose members are lowering — `super` binds lexically to it
1449
1481
  * (arrows inside methods lower within this window, so they see it too). */
1450
1482
  currentClass = null;
@@ -1583,6 +1615,7 @@ export class Lowerer {
1583
1615
  * a reference to a lowerable body reports its name here — recorded even
1584
1616
  * when the enclosing statement later poisons. */
1585
1617
  onEdge = null;
1618
+ deferredModuleInitializers = null;
1586
1619
  // Stack of function contexts (bottom = the function being declared at
1587
1620
  // top level, top = the innermost nested function currently lowering).
1588
1621
  fnStack = [];
@@ -1621,6 +1654,15 @@ export class Lowerer {
1621
1654
  * is assembled directly. The configured reachable set remains null so
1622
1655
  * demand-driven instance lowering keeps its existing gates. */
1623
1656
  reachableForArtifacts = null;
1657
+ /** Constructors retained by the active worklist. A boxed base receiver
1658
+ * can contain any retained descendant, but importing its declaration
1659
+ * alone does not make every descendant constructible. */
1660
+ constructedClasses = null;
1661
+ virtualEdges = new Map();
1662
+ classCanBeConstructed(info) {
1663
+ return this.constructedClasses === null || this.constructedClasses.has(info.def.name) ||
1664
+ info.genericInstance !== undefined || info.mixinInstance !== undefined;
1665
+ }
1624
1666
  /** Coverage remainder mode: the reachability gate inverts (see wantBody)
1625
1667
  * and no module is built. */
1626
1668
  remainder;
@@ -2467,8 +2509,11 @@ export class Lowerer {
2467
2509
  if (!symbol)
2468
2510
  return null;
2469
2511
  const g = this.globalsBySymbol.get(symbol);
2470
- if (g)
2512
+ if (g) {
2513
+ if (g.type.kind === "func")
2514
+ g.type = this.runtimeOptionalBindingType(ident, g.type);
2471
2515
  return g;
2516
+ }
2472
2517
  for (const d of this.checker.declarationsOf(symbol)) {
2473
2518
  const byDecl = this.globalsByDeclNode.get(d);
2474
2519
  if (byDecl)
@@ -2713,6 +2758,14 @@ export class Lowerer {
2713
2758
  return null;
2714
2759
  return s.flags & ts.SymbolFlags.Alias ? this.checker.getAliasedSymbol(s) : s;
2715
2760
  };
2761
+ const signatureOf = (node) => {
2762
+ const symbol = symbolOf(node);
2763
+ if (!symbol)
2764
+ return null;
2765
+ const projection = this.staticCallables.get(symbol);
2766
+ return this.fnSigsBySymbol.get(symbol) ??
2767
+ (projection?.kind === "declared-function" ? projection.signature : null);
2768
+ };
2716
2769
  const functionDeclBySymbol = new Map();
2717
2770
  const signatureBySymbol = new Map();
2718
2771
  const methodFamilies = new Map();
@@ -2866,9 +2919,11 @@ export class Lowerer {
2866
2919
  }
2867
2920
  if (ts.isBinaryExpression(e)) {
2868
2921
  const op = e.operatorToken.kind;
2869
- if (op === ts.SyntaxKind.AmpersandAmpersandToken ||
2870
- op === ts.SyntaxKind.BarBarToken ||
2871
- op === ts.SyntaxKind.QuestionQuestionToken)
2922
+ // Nullish/falsy left values select the fallback, so only that
2923
+ // fallback can make the whole expression undefined.
2924
+ if (op === ts.SyntaxKind.BarBarToken || op === ts.SyntaxKind.QuestionQuestionToken)
2925
+ return mayBeOptional(e.right);
2926
+ if (op === ts.SyntaxKind.AmpersandAmpersandToken)
2872
2927
  return mayBeOptional(e.left) || mayBeOptional(e.right);
2873
2928
  }
2874
2929
  if (ts.isPropertyAccessExpression(e) && ts.isIdentifier(e.expression)) {
@@ -2994,6 +3049,29 @@ export class Lowerer {
2994
3049
  found = true;
2995
3050
  return found;
2996
3051
  };
3052
+ const jsLambdas = [];
3053
+ for (const sf of sourceFiles) {
3054
+ if (!isJsSourceFile(sf))
3055
+ continue;
3056
+ ts.walkPreorder(sf, (node) => {
3057
+ if (ts.isArrowFunction(node) || ts.isFunctionExpression(node))
3058
+ jsLambdas.push(node);
3059
+ });
3060
+ }
3061
+ for (const [symbol, signature] of signatureBySymbol) {
3062
+ const declaration = functionDeclBySymbol.get(symbol);
3063
+ if (!declaration || !isJsSourceFile(declaration.getSourceFile()))
3064
+ continue;
3065
+ const checked = this.checker.getSignatureFromDeclaration(declaration);
3066
+ const checkedReturn = checked ? this.checker.getReturnTypeOfSignature(checked) : null;
3067
+ // Checker-known optional results already narrow at each use. Only
3068
+ // propagate undefined that JavaScript's runtime ABI adds beyond them.
3069
+ if (checkedReturn && ((checkedReturn.flags & ts.TypeFlags.Undefined) !== 0 ||
3070
+ checkedReturn.isUnionType() && ts.constituentTypes(checkedReturn).some((arm) => (arm.flags & ts.TypeFlags.Undefined) !== 0)))
3071
+ continue;
3072
+ if (signature.returnType.kind === "union" && this.armTag(signature.returnType.unionId, UNDEFINED_T) >= 0)
3073
+ optionalReturns.add(symbol);
3074
+ }
2997
3075
  const promoteHofCallback = (callback, parameterIndices, seen = new Set()) => {
2998
3076
  let changed = false;
2999
3077
  const checkerTypeContainsTypeParameter = (type) => {
@@ -3431,6 +3509,23 @@ export class Lowerer {
3431
3509
  for (const [symbol, decl] of functionDeclBySymbol)
3432
3510
  if (scanReturns(symbol, decl))
3433
3511
  changed = true;
3512
+ for (const fn of jsLambdas) {
3513
+ if (!bodyReturnsOptional(fn))
3514
+ continue;
3515
+ const mapped = this.mapTypeOf(this.typeOf(fn));
3516
+ if (mapped?.kind !== "func")
3517
+ continue;
3518
+ const previous = this.runtimeOptionalFunctionReturnType(fn, mapped.ret);
3519
+ if (previous.kind === "generator")
3520
+ continue;
3521
+ const next = previous.kind === "promise"
3522
+ ? { ...previous, inner: this.runtimeOptionalType(previous.inner) }
3523
+ : this.runtimeOptionalType(previous);
3524
+ if (!typeEquals(previous, next)) {
3525
+ this.runtimeOptionalFunctionReturns.set(fn, next);
3526
+ changed = true;
3527
+ }
3528
+ }
3434
3529
  // Every implementation of a virtual slot must retain the same ABI,
3435
3530
  // including when just one body forwards an omitted parameter.
3436
3531
  for (const family of optionalMethodFamilies) {
@@ -3475,6 +3570,14 @@ export class Lowerer {
3475
3570
  this.runtimeOptionalFunctionReturns.set(decl, arithmetic);
3476
3571
  }
3477
3572
  }
3573
+ for (const [declaration, global] of this.globalsByDeclNode) {
3574
+ if (global.type.kind !== "func" || !ts.isBinaryExpression(declaration) || !isJsSourceFile(declaration.getSourceFile()))
3575
+ continue;
3576
+ const value = peel(declaration.right);
3577
+ if (!ts.isFunctionExpression(value) && !ts.isArrowFunction(value))
3578
+ continue;
3579
+ global.type = { ...global.type, ret: this.runtimeOptionalFunctionReturnType(value, global.type.ret) };
3580
+ }
3478
3581
  for (const sf of sourceFiles) {
3479
3582
  ts.walkPreorder(sf, (node) => {
3480
3583
  if (!ts.isVariableDeclaration(node) || !ts.isIdentifier(node.name))
@@ -3482,6 +3585,23 @@ export class Lowerer {
3482
3585
  const symbol = symbolOf(node.name);
3483
3586
  if (!symbol)
3484
3587
  return;
3588
+ if (isJsSourceFile(sf) && !node.type && !hasJsTypeAnnotation(node) && node.initializer &&
3589
+ (ts.isArrowFunction(node.initializer) || ts.isFunctionExpression(node.initializer))) {
3590
+ const global = this.globalsBySymbol.get(symbol);
3591
+ if (global?.type.kind === "func")
3592
+ global.type = { ...global.type, ret: this.runtimeOptionalFunctionReturnType(node.initializer, global.type.ret) };
3593
+ }
3594
+ if (!node.type && !hasJsTypeAnnotation(node) && node.initializer && ts.isIdentifier(node.initializer)) {
3595
+ const global = this.globalsBySymbol.get(symbol);
3596
+ const current = global?.type ?? this.mapTypeOf(this.typeOf(node.name));
3597
+ const source = current?.kind === "func" ? signatureOf(node.initializer) : null;
3598
+ if (source && current?.kind === "func") {
3599
+ const promoted = { ...current, params: source.params.filter((param) => param.mode !== "dynRest" && param.mode !== "arguments").map((param) => param.type), ret: source.returnType };
3600
+ this.runtimeOptionalBindingTypes.set(symbol, promoted);
3601
+ if (global)
3602
+ global.type = promoted;
3603
+ }
3604
+ }
3485
3605
  const fields = optionalFields.get(symbol);
3486
3606
  if (!dynamicObjectEntryRows.has(symbol) && !optionalSymbols.has(symbol) && !fields)
3487
3607
  return;
@@ -3492,7 +3612,7 @@ export class Lowerer {
3492
3612
  if (!dynamicObjectEntryRows.has(symbol) && optionalSymbols.has(symbol))
3493
3613
  promoted = addUndefined(promoted);
3494
3614
  if (promoted.kind === "func" && node.initializer && ts.isIdentifier(node.initializer)) {
3495
- const sourceSig = this.fnSigOf(node.initializer);
3615
+ const sourceSig = signatureOf(node.initializer);
3496
3616
  if (sourceSig) {
3497
3617
  promoted = {
3498
3618
  ...promoted,
@@ -3692,6 +3812,7 @@ export class Lowerer {
3692
3812
  * and the retained reachability worklist. */
3693
3813
  finishModule(functions) {
3694
3814
  finalizeClassMethodValues(this, functions);
3815
+ trackClassFieldCreation(this, functions);
3695
3816
  // Globals typed by a class that never REGISTERED (a JS class whose
3696
3817
  // collection fenced — Symbol-keyed fields, an unsupported base): the
3697
3818
  // declaration statement and every use compiled to runtime fences, but
@@ -3862,6 +3983,7 @@ export class Lowerer {
3862
3983
  * body; both fire edges through the same hooks and are not units
3863
3984
  * themselves. */
3864
3985
  emitReachable(extraRoots) {
3986
+ this.deferredModuleInitializers = new DeferredModuleInitializers();
3865
3987
  const parts = this.splitFiles();
3866
3988
  // Direct lowering callers do not necessarily run program preflight.
3867
3989
  // Establish the same managed header/top-level batch here before
@@ -4028,6 +4150,7 @@ export class Lowerer {
4028
4150
  return owner;
4029
4151
  };
4030
4152
  const reachable = new Set();
4153
+ this.constructedClasses = new Set();
4031
4154
  const queue = [];
4032
4155
  const loweredUnits = new Map();
4033
4156
  const initFunctions = [];
@@ -4038,6 +4161,12 @@ export class Lowerer {
4038
4161
  reachable.add(name);
4039
4162
  if (units.has(name))
4040
4163
  queue.push(name);
4164
+ if (this.constructedClasses && name.endsWith(".constructor")) {
4165
+ this.constructedClasses.add(name.slice(1, -".constructor".length));
4166
+ for (const [owner, methods] of this.virtualEdges)
4167
+ for (const method of methods)
4168
+ this.noteVirtualEdge(owner, method);
4169
+ }
4041
4170
  };
4042
4171
  // Class EXPRESSIONS collect while init bodies lower (below): their
4043
4172
  // member units register the moment collection finishes — before any
@@ -4188,10 +4317,13 @@ export class Lowerer {
4188
4317
  const classDispatch = new ClassDynamicDispatch(extraRoots !== undefined);
4189
4318
  for (;;) {
4190
4319
  drainInstances();
4320
+ const initializerChanged = this.deferredModuleInitializers.process(this, [
4321
+ ...loweredUnits.values(), ...initFunctions, ...instanceFunctions, ...this.liftedFns, ...this.implicitFns,
4322
+ ]);
4191
4323
  const dispatchChanged = classDispatch.process(this, [
4192
4324
  ...loweredUnits.values(), ...initFunctions, ...instanceFunctions, ...this.liftedFns, ...this.implicitFns,
4193
4325
  ]);
4194
- if (queue.length === 0 && !dispatchChanged)
4326
+ if (queue.length === 0 && !dispatchChanged && !initializerChanged)
4195
4327
  break;
4196
4328
  drainUnits();
4197
4329
  this.restoreGenericInstanceOrder(instLowered);
@@ -4214,6 +4346,20 @@ export class Lowerer {
4214
4346
  ...this.liftedFns,
4215
4347
  ...this.implicitFns,
4216
4348
  ];
4349
+ // The worklist can leave a virtual site with only its base method.
4350
+ // Devirtualize after construction/override reachability has settled.
4351
+ for (const fn of functions)
4352
+ fn.body = transformStmtList(fn.body, { stmt: (statement) => statement, expr: (expression) => {
4353
+ if (expression.kind !== "virtualCall")
4354
+ return expression;
4355
+ const info = this.classes.get(expression.className);
4356
+ const method = info && this.findMethodOn(info, expression.method);
4357
+ if (!method || method.sig.abstract || [...this.classes.values()].some((candidate) => this.isSubclassOf(candidate.def.name, expression.className) && candidate.def.name !== expression.className &&
4358
+ candidate.methods.has(expression.method) && reachable.has(`%${candidate.def.name}.${expression.method}`)))
4359
+ return expression;
4360
+ return { kind: "call", callee: `%${method.declarer.def.name}.${expression.method}`,
4361
+ args: [this.upcastTo(expression.args[0], method.declarer.def.name), ...expression.args.slice(1)], type: expression.type, loc: expression.loc };
4362
+ } });
4217
4363
  this.reachableForArtifacts = reachable;
4218
4364
  return { reachable, result: this.finishModule(functions) };
4219
4365
  }
@@ -4231,12 +4377,17 @@ export class Lowerer {
4231
4377
  noteVirtualEdge(info, method) {
4232
4378
  if (!this.onEdge)
4233
4379
  return;
4380
+ if (this.constructedClasses) {
4381
+ const methods = this.virtualEdges.get(info) ?? new Set();
4382
+ methods.add(method);
4383
+ this.virtualEdges.set(info, methods);
4384
+ }
4234
4385
  const above = this.findMethodOn(info, method);
4235
4386
  if (above)
4236
4387
  this.noteEdge(`%${above.declarer.def.name}.${method}`);
4237
4388
  const below = (c) => {
4238
4389
  for (const s of c.subclasses) {
4239
- if (s.methods.has(method))
4390
+ if (this.classCanBeConstructed(s) && s.methods.has(method))
4240
4391
  this.noteEdge(`%${s.def.name}.${method}`);
4241
4392
  below(s);
4242
4393
  }
@@ -4587,6 +4738,16 @@ export class Lowerer {
4587
4738
  return fenceStaticReadableStreamMember(this, access, use);
4588
4739
  }
4589
4740
  typeOf(node) {
4741
+ if (ts.isPropertyAccessExpression(node) && isJsSourceFile(node.getSourceFile())) {
4742
+ const receiver = node.expression.kind === ts.SyntaxKind.ThisKeyword && this.fnStack.length > 0
4743
+ ? this.resolveThis()?.type : this.mapTypeOf(this.checker.getTypeAtLocation(node.expression));
4744
+ const checkedThis = node.expression.kind === ts.SyntaxKind.ThisKeyword && this.fnStack.length > 0 && receiver?.kind === "dyn"
4745
+ ? this.currentClass : null;
4746
+ if (receiver?.kind === "object" && this.classes.get(receiver.className)?.fields.get(node.name.text)?.kind === "dyn" ||
4747
+ checkedThis?.fields.get(node.name.text)?.kind === "dyn") {
4748
+ return this.checker.getUnknownType();
4749
+ }
4750
+ }
4590
4751
  // A checked JS method receives its actual call-site receiver. Its
4591
4752
  // declaration's inferred class type must not turn property reads back
4592
4753
  // into native field loads when the method is borrowed by another object.
@@ -4637,8 +4798,15 @@ export class Lowerer {
4637
4798
  // A checked value can contain any runtime kind. A checker-proven
4638
4799
  // branch narrow therefore cannot contradict this specialization;
4639
4800
  // reads still validate the payload through maybeNarrow.
4640
- if (boundIr.kind === "dyn")
4641
- return t;
4801
+ if (boundIr.kind === "dyn") {
4802
+ // JSDoc and initializer inference are declaration types, not flow
4803
+ // proofs. A checked specialization must not reinstate those
4804
+ // stale layouts (mutable/null slots and heterogeneous JS arrays).
4805
+ const declaration = sym && this.checker.valueDeclarationOf(sym);
4806
+ const declared = declaration && ts.isParameter(declaration)
4807
+ ? this.mapTypeOf(this.checker.getTypeAtLocation(declaration.name)) : null;
4808
+ return declared && typeEquals(declared, narrowedIr) ? bound : t;
4809
+ }
4642
4810
  // A union binding narrowed to one of its arms (typeof/equality
4643
4811
  // guards over string|number bindings) — the narrow is truth.
4644
4812
  if (boundIr.kind === "union") {
@@ -5063,7 +5231,14 @@ export class Lowerer {
5063
5231
  // undefined/null literals store the dyn unit values. Types outside the
5064
5232
  // dyn's domain (bytes, classes, Maps, ...) fall through to
5065
5233
  // requireExactShape's SC1101 fence.
5066
- // A promise flowing into a VOID-promise slot (an inferred
5234
+ // Promise payloads may widen at a checked return boundary, including
5235
+ // arrays inferred as tuple results by Promise.all. Keep both payload
5236
+ // ABIs explicit: box settlement, then validate the destination payload.
5237
+ if (expected.kind === "promise" && expected.inner.kind !== "void" && expr.type.kind === "promise" &&
5238
+ !typeEquals(expected, expr.type) && this.dynConvertible(expr.type) &&
5239
+ canDynCheckTo(expected, (id) => this.shapes.get(id), (id) => this.unions.get(id))) {
5240
+ return { kind: "dynCheck", value: this.coerceToExpected(expr, DYN), type: expected, loc: expr.loc };
5241
+ }
5067
5242
  // Promise<never> return holding a `return Promise.reject(value)` the
5068
5243
  // dyn arm typed promise<dyn>): awaiting through the slot ignores the
5069
5244
  // fulfillment payload (scr_await_void) and rejections flow untyped,
@@ -7749,7 +7924,7 @@ export class Lowerer {
7749
7924
  // NamedEvaluation through a variable initializer) — inspect prints
7750
7925
  // [Function: name] and call errors spell it, like Node.
7751
7926
  if (e.kind === "dynFrom" && e.value.type.kind === "func" && e.fnName === undefined) {
7752
- const name = jsFuncNameOf(node);
7927
+ const name = jsFuncNameOf(node, this);
7753
7928
  if (name !== null)
7754
7929
  e = { ...e, fnName: name };
7755
7930
  }
@@ -8039,7 +8214,7 @@ export class Lowerer {
8039
8214
  }
8040
8215
  }
8041
8216
  let e = this.lowerExpr(node);
8042
- if (expected?.kind === "union" && this.armTag(expected.unionId, UNDEFINED_T) >= 0) {
8217
+ if (expected?.kind === "union" && this.armTag(expected.unionId, UNDEFINED_T) >= 0 || expected?.kind === "dyn" && isJsSourceFile(node.getSourceFile())) {
8043
8218
  // A destination that accepts undefined must retain an unchecked
8044
8219
  // read's storage value even when the checker still calls it present.
8045
8220
  e = this.runtimeOptionalSourceValue(node, e) ?? e;
@@ -8100,7 +8275,19 @@ export class Lowerer {
8100
8275
  * declared result type of an index-signature read under
8101
8276
  * noUncheckedIndexedAccess. Null when the type cannot take the arm. */
8102
8277
  withUndefinedArmOf(t) {
8103
- return withUndefinedArmCanonical(t, this.unions);
8278
+ if (t.kind !== "union")
8279
+ return withUndefinedArmCanonical(t, this.unions);
8280
+ const cached = this.addedUndefinedArms.get(t.unionId);
8281
+ if (cached && cached.unions === this.unions.revision)
8282
+ return cached.type;
8283
+ // As with removing undefined, repeated optional-read propagation can
8284
+ // reuse the exact union transformation until a recursive contract closes.
8285
+ // An unknown id is not cached: a later interning can create it.
8286
+ if (!this.unions.get(t.unionId))
8287
+ return null;
8288
+ const type = withUndefinedArmCanonical(t, this.unions);
8289
+ this.addedUndefinedArms.set(t.unionId, { type, unions: this.unions.revision });
8290
+ return type;
8104
8291
  }
8105
8292
  /** True when a static type converts to a dyn value (the dynFrom
8106
8293
  * walker's domain): JSON-safe, bytes<u8> (Uint8Array/Buffer — the checked-dynamic tree's
@@ -9755,6 +9942,10 @@ export class Lowerer {
9755
9942
  * member access that IS a module in its own right (`fs.promises` — the
9756
9943
  * same object as node:fs/promises, Node's rule). Null otherwise. */
9757
9944
  builtinNamespaceModuleOf(expr) {
9945
+ // Default and CommonJS process bindings alias the global object, whose
9946
+ // methods and properties keep their existing process lowerings.
9947
+ if (stdlibGlobalNameOf(this, expr) === "process")
9948
+ return null;
9758
9949
  const stored = ts.isIdentifier(expr)
9759
9950
  ? (this.peekLocal(expr)?.type ?? this.globalOf(expr)?.type)
9760
9951
  : undefined;