@scriptc/compiler 0.2.0 → 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 (284) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +84 -19
  2. package/dist/backend/cycle-analysis.js +1 -0
  3. package/dist/backend/cycle-analysis.js.map +1 -1
  4. package/dist/backend/llvm/classes.js +21 -5
  5. package/dist/backend/llvm/classes.js.map +1 -1
  6. package/dist/backend/llvm/dyn.d.ts +8 -0
  7. package/dist/backend/llvm/dyn.js +247 -108
  8. package/dist/backend/llvm/dyn.js.map +1 -1
  9. package/dist/backend/llvm/emitter.d.ts +6 -3
  10. package/dist/backend/llvm/emitter.js +99 -25
  11. package/dist/backend/llvm/emitter.js.map +1 -1
  12. package/dist/backend/llvm/emitter.test.js +9 -1
  13. package/dist/backend/llvm/emitter.test.js.map +1 -1
  14. package/dist/backend/llvm/expr-bytes.d.ts +1 -1
  15. package/dist/backend/llvm/expr-bytes.js +28 -17
  16. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  17. package/dist/backend/llvm/expr-containers.js +5 -0
  18. package/dist/backend/llvm/expr-containers.js.map +1 -1
  19. package/dist/backend/llvm/expr-control.js +1 -1
  20. package/dist/backend/llvm/expr-control.js.map +1 -1
  21. package/dist/backend/llvm/expr-dynamic.js +47 -13
  22. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  23. package/dist/backend/llvm/expr-primitives.js +11 -1
  24. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  25. package/dist/backend/llvm/expr-records.js +11 -3
  26. package/dist/backend/llvm/expr-records.js.map +1 -1
  27. package/dist/backend/llvm/expr-stream-bridges.js +187 -18
  28. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  29. package/dist/backend/llvm/expr-stream-callbacks.d.ts +2 -2
  30. package/dist/backend/llvm/expr-stream-callbacks.js +7 -57
  31. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
  32. package/dist/backend/llvm/lib-dispatch.js +41 -3
  33. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  34. package/dist/backend/llvm/lib-filesystem.js +12 -9
  35. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  36. package/dist/backend/llvm/lib-process.js +23 -3
  37. package/dist/backend/llvm/lib-process.js.map +1 -1
  38. package/dist/backend/llvm/lib-shared.js +80 -3
  39. package/dist/backend/llvm/lib-shared.js.map +1 -1
  40. package/dist/backend/llvm/shapes.js +8 -2
  41. package/dist/backend/llvm/shapes.js.map +1 -1
  42. package/dist/backend/may-throw.js +4 -0
  43. package/dist/backend/may-throw.js.map +1 -1
  44. package/dist/backend/native-codegen.d.ts +1 -1
  45. package/dist/backend/native-codegen.js +4 -3
  46. package/dist/backend/native-codegen.js.map +1 -1
  47. package/dist/backend/native-codegen.test.js +11 -0
  48. package/dist/backend/native-codegen.test.js.map +1 -1
  49. package/dist/backend/native-toolchain.d.ts +3 -6
  50. package/dist/backend/native-toolchain.js +53 -23
  51. package/dist/backend/native-toolchain.js.map +1 -1
  52. package/dist/backend/native-toolchain.test.js +72 -0
  53. package/dist/backend/native-toolchain.test.js.map +1 -1
  54. package/dist/backend/runtime-abi.d.ts +2 -2
  55. package/dist/backend/runtime-abi.js +2 -2
  56. package/dist/backend/runtime-pack-native.js +4 -1
  57. package/dist/backend/runtime-pack-native.js.map +1 -1
  58. package/dist/backend/runtime-pack-targets.test.js +1 -1
  59. package/dist/backend/runtime-pack.test.js +1 -1
  60. package/dist/backend/target-diagnostics.d.ts +5 -0
  61. package/dist/backend/target-diagnostics.js +72 -1
  62. package/dist/backend/target-diagnostics.js.map +1 -1
  63. package/dist/backend/target-diagnostics.test.d.ts +1 -0
  64. package/dist/backend/target-diagnostics.test.js +68 -0
  65. package/dist/backend/target-diagnostics.test.js.map +1 -0
  66. package/dist/backend/targets.js +10 -6
  67. package/dist/backend/targets.js.map +1 -1
  68. package/dist/backend/targets.test.js +7 -0
  69. package/dist/backend/targets.test.js.map +1 -1
  70. package/dist/compat/fetch-profile.js +34 -4
  71. package/dist/compat/fetch-profile.js.map +1 -1
  72. package/dist/coverage/surface-manifest.js +5 -3
  73. package/dist/coverage/surface-manifest.js.map +1 -1
  74. package/dist/diagnostics/diagnostic.js +2 -7
  75. package/dist/diagnostics/diagnostic.js.map +1 -1
  76. package/dist/executable/executable-cache.d.ts +7 -3
  77. package/dist/executable/executable-cache.js +47 -11
  78. package/dist/executable/executable-cache.js.map +1 -1
  79. package/dist/executable/executable-cache.test.js +109 -2
  80. package/dist/executable/executable-cache.test.js.map +1 -1
  81. package/dist/executable/prepare.js +2 -1
  82. package/dist/executable/prepare.js.map +1 -1
  83. package/dist/frontend/builtin-modules.d.ts +1 -1
  84. package/dist/frontend/builtin-modules.js +1 -1
  85. package/dist/frontend/builtin-modules.js.map +1 -1
  86. package/dist/frontend/function-completion.d.ts +6 -0
  87. package/dist/frontend/function-completion.js +50 -0
  88. package/dist/frontend/function-completion.js.map +1 -0
  89. package/dist/frontend/lowering/abstract-equality.js +5 -1
  90. package/dist/frontend/lowering/abstract-equality.js.map +1 -1
  91. package/dist/frontend/lowering/checked-iterable-spread.d.ts +4 -0
  92. package/dist/frontend/lowering/checked-iterable-spread.js +30 -0
  93. package/dist/frontend/lowering/checked-iterable-spread.js.map +1 -0
  94. package/dist/frontend/lowering/checked-promise-all.d.ts +5 -0
  95. package/dist/frontend/lowering/checked-promise-all.js +31 -0
  96. package/dist/frontend/lowering/checked-promise-all.js.map +1 -0
  97. package/dist/frontend/lowering/class-callbacks.d.ts +4 -4
  98. package/dist/frontend/lowering/class-callbacks.js +29 -17
  99. package/dist/frontend/lowering/class-callbacks.js.map +1 -1
  100. package/dist/frontend/lowering/class-construction.d.ts +14 -0
  101. package/dist/frontend/lowering/class-construction.js +185 -0
  102. package/dist/frontend/lowering/class-construction.js.map +1 -0
  103. package/dist/frontend/lowering/class-descriptors.d.ts +2 -1
  104. package/dist/frontend/lowering/class-descriptors.js +58 -10
  105. package/dist/frontend/lowering/class-descriptors.js.map +1 -1
  106. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +36 -1
  107. package/dist/frontend/lowering/class-dynamic-dispatch.js +965 -91
  108. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  109. package/dist/frontend/lowering/class-dynamic-dispatch.test.js +66 -3
  110. package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
  111. package/dist/frontend/lowering/class-instance-constructor.d.ts +1 -1
  112. package/dist/frontend/lowering/class-instance-constructor.js +15 -42
  113. package/dist/frontend/lowering/class-instance-constructor.js.map +1 -1
  114. package/dist/frontend/lowering/class-method-values.d.ts +20 -1
  115. package/dist/frontend/lowering/class-method-values.js +120 -24
  116. package/dist/frontend/lowering/class-method-values.js.map +1 -1
  117. package/dist/frontend/lowering/class-prototypes.d.ts +10 -3
  118. package/dist/frontend/lowering/class-prototypes.js +188 -21
  119. package/dist/frontend/lowering/class-prototypes.js.map +1 -1
  120. package/dist/frontend/lowering/class-runtime-statics.d.ts +8 -0
  121. package/dist/frontend/lowering/class-runtime-statics.js +84 -0
  122. package/dist/frontend/lowering/class-runtime-statics.js.map +1 -0
  123. package/dist/frontend/lowering/class-static-data.d.ts +1 -0
  124. package/dist/frontend/lowering/class-static-data.js +6 -4
  125. package/dist/frontend/lowering/class-static-data.js.map +1 -1
  126. package/dist/frontend/lowering/containers/bytes.js +66 -17
  127. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  128. package/dist/frontend/lowering/containers/string-and-regexp.js +24 -47
  129. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  130. package/dist/frontend/lowering/deferred-module-initializers.d.ts +13 -0
  131. package/dist/frontend/lowering/deferred-module-initializers.js +410 -0
  132. package/dist/frontend/lowering/deferred-module-initializers.js.map +1 -0
  133. package/dist/frontend/lowering/deferred-module-initializers.test.d.ts +1 -0
  134. package/dist/frontend/lowering/deferred-module-initializers.test.js +92 -0
  135. package/dist/frontend/lowering/deferred-module-initializers.test.js.map +1 -0
  136. package/dist/frontend/lowering/error-methods.d.ts +4 -1
  137. package/dist/frontend/lowering/error-methods.js +100 -1
  138. package/dist/frontend/lowering/error-methods.js.map +1 -1
  139. package/dist/frontend/lowering/expressions/native-proxy.js +3 -1
  140. package/dist/frontend/lowering/expressions/native-proxy.js.map +1 -1
  141. package/dist/frontend/lowering/expressions/nullish-assignment.js +19 -11
  142. package/dist/frontend/lowering/expressions/nullish-assignment.js.map +1 -1
  143. package/dist/frontend/lowering/expressions/object-literals.js +68 -7
  144. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  145. package/dist/frontend/lowering/expressions/optional-chains.d.ts +3 -4
  146. package/dist/frontend/lowering/expressions/optional-chains.js +72 -20
  147. package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
  148. package/dist/frontend/lowering/function-context.d.ts +11 -3
  149. package/dist/frontend/lowering/function-context.js +11 -5
  150. package/dist/frontend/lowering/function-context.js.map +1 -1
  151. package/dist/frontend/lowering/generator-dynamic-dispatch.d.ts +1 -0
  152. package/dist/frontend/lowering/generator-dynamic-dispatch.js +39 -1
  153. package/dist/frontend/lowering/generator-dynamic-dispatch.js.map +1 -1
  154. package/dist/frontend/lowering/lib-boundary.d.ts +2 -0
  155. package/dist/frontend/lowering/lib-boundary.js +54 -1
  156. package/dist/frontend/lowering/lib-boundary.js.map +1 -1
  157. package/dist/frontend/lowering/lower-builtin-values.d.ts +7 -1
  158. package/dist/frontend/lowering/lower-builtin-values.js +113 -3
  159. package/dist/frontend/lowering/lower-builtin-values.js.map +1 -1
  160. package/dist/frontend/lowering/lower-builtins.d.ts +10 -14
  161. package/dist/frontend/lowering/lower-builtins.js +443 -88
  162. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  163. package/dist/frontend/lowering/lower-calls.d.ts +8 -5
  164. package/dist/frontend/lowering/lower-calls.js +717 -142
  165. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  166. package/dist/frontend/lowering/lower-classes.d.ts +18 -13
  167. package/dist/frontend/lowering/lower-classes.js +1076 -188
  168. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  169. package/dist/frontend/lowering/lower-containers.d.ts +9 -0
  170. package/dist/frontend/lowering/lower-containers.js +172 -51
  171. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  172. package/dist/frontend/lowering/lower-dgram.js +3 -2
  173. package/dist/frontend/lowering/lower-dgram.js.map +1 -1
  174. package/dist/frontend/lowering/lower-exprs.d.ts +12 -8
  175. package/dist/frontend/lowering/lower-exprs.js +802 -232
  176. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  177. package/dist/frontend/lowering/lower-generators.js +17 -2
  178. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  179. package/dist/frontend/lowering/lower-inspect.js +15 -1
  180. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  181. package/dist/frontend/lowering/lower-island.d.ts +2 -0
  182. package/dist/frontend/lowering/lower-island.js +36 -10
  183. package/dist/frontend/lowering/lower-island.js.map +1 -1
  184. package/dist/frontend/lowering/lower-island.test.d.ts +1 -0
  185. package/dist/frontend/lowering/lower-island.test.js +51 -0
  186. package/dist/frontend/lowering/lower-island.test.js.map +1 -0
  187. package/dist/frontend/lowering/lower-modules.d.ts +1 -3
  188. package/dist/frontend/lowering/lower-modules.js +380 -73
  189. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  190. package/dist/frontend/lowering/lower-modules.test.d.ts +1 -0
  191. package/dist/frontend/lowering/lower-modules.test.js +107 -0
  192. package/dist/frontend/lowering/lower-modules.test.js.map +1 -0
  193. package/dist/frontend/lowering/lower-stmts.d.ts +7 -3
  194. package/dist/frontend/lowering/lower-stmts.js +221 -47
  195. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  196. package/dist/frontend/lowering/lower-stmts.test.d.ts +1 -0
  197. package/dist/frontend/lowering/lower-stmts.test.js +77 -0
  198. package/dist/frontend/lowering/lower-stmts.test.js.map +1 -0
  199. package/dist/frontend/lowering/lower-stream.js +3 -1
  200. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  201. package/dist/frontend/lowering/lower-url.d.ts +2 -1
  202. package/dist/frontend/lowering/lower-url.js +32 -9
  203. package/dist/frontend/lowering/lower-url.js.map +1 -1
  204. package/dist/frontend/lowering/lowerer.d.ts +53 -10
  205. package/dist/frontend/lowering/lowerer.js +390 -77
  206. package/dist/frontend/lowering/lowerer.js.map +1 -1
  207. package/dist/frontend/lowering/lowerer.test.js +187 -3
  208. package/dist/frontend/lowering/lowerer.test.js.map +1 -1
  209. package/dist/frontend/lowering/module-namespace-elements.d.ts +7 -0
  210. package/dist/frontend/lowering/module-namespace-elements.js +54 -0
  211. package/dist/frontend/lowering/module-namespace-elements.js.map +1 -0
  212. package/dist/frontend/lowering/object-factory-new.d.ts +4 -3
  213. package/dist/frontend/lowering/object-factory-new.js +27 -14
  214. package/dist/frontend/lowering/object-factory-new.js.map +1 -1
  215. package/dist/frontend/lowering/surfaces.d.ts +3 -0
  216. package/dist/frontend/lowering/surfaces.js +48 -19
  217. package/dist/frontend/lowering/surfaces.js.map +1 -1
  218. package/dist/frontend/lowering/text-decoder-encoding.d.ts +2 -0
  219. package/dist/frontend/lowering/text-decoder-encoding.js +8 -0
  220. package/dist/frontend/lowering/text-decoder-encoding.js.map +1 -1
  221. package/dist/frontend/lowering/text-decoder-encoding.test.js +2 -1
  222. package/dist/frontend/lowering/text-decoder-encoding.test.js.map +1 -1
  223. package/dist/frontend/lowering/unregistered-class-types.test.js +3 -3
  224. package/dist/frontend/lowering/unregistered-class-types.test.js.map +1 -1
  225. package/dist/frontend/npm-static-prune.js +116 -34
  226. package/dist/frontend/npm-static-prune.js.map +1 -1
  227. package/dist/frontend/npm-static-prune.test.js +8 -0
  228. package/dist/frontend/npm-static-prune.test.js.map +1 -1
  229. package/dist/frontend/program.d.ts +1 -1
  230. package/dist/frontend/program.js +57 -26
  231. package/dist/frontend/program.js.map +1 -1
  232. package/dist/frontend/program.test.js +18 -0
  233. package/dist/frontend/program.test.js.map +1 -1
  234. package/dist/frontend/ts7/ast.js +4 -3
  235. package/dist/frontend/ts7/ast.js.map +1 -1
  236. package/dist/frontend/ts7/semantic-json.js +5 -10
  237. package/dist/frontend/ts7/semantic-json.js.map +1 -1
  238. package/dist/frontend/type-mapper.d.ts +9 -1
  239. package/dist/frontend/type-mapper.js +169 -23
  240. package/dist/frontend/type-mapper.js.map +1 -1
  241. package/dist/frontend/type-mapper.test.js +23 -0
  242. package/dist/frontend/type-mapper.test.js.map +1 -1
  243. package/dist/frontend/union-discriminants.d.ts +1 -1
  244. package/dist/frontend/union-discriminants.js +24 -9
  245. package/dist/frontend/union-discriminants.js.map +1 -1
  246. package/dist/index.js +16 -10
  247. package/dist/index.js.map +1 -1
  248. package/dist/ir/analysis.js +2 -0
  249. package/dist/ir/analysis.js.map +1 -1
  250. package/dist/ir/ir.d.ts +74 -41
  251. package/dist/ir/ir.js +167 -43
  252. package/dist/ir/ir.js.map +1 -1
  253. package/dist/ir/ir.test.js +35 -0
  254. package/dist/ir/ir.test.js.map +1 -1
  255. package/dist/ir/serialize.js +35 -3
  256. package/dist/ir/serialize.js.map +1 -1
  257. package/dist/ir/serialize.test.js +26 -1
  258. package/dist/ir/serialize.test.js.map +1 -1
  259. package/dist/ir/traverse.d.ts +0 -3
  260. package/dist/ir/traverse.js +33 -20
  261. package/dist/ir/traverse.js.map +1 -1
  262. package/dist/ir/validate.js +136 -16
  263. package/dist/ir/validate.js.map +1 -1
  264. package/dist/ir/validate.test.js +77 -1
  265. package/dist/ir/validate.test.js.map +1 -1
  266. package/dist/library/compiler-self-identity.js +1 -1
  267. package/dist/library/compiler-self-identity.test.js +2 -2
  268. package/dist/library/compiler-self-identity.test.js.map +1 -1
  269. package/dist/library/int-infer.d.ts +2 -2
  270. package/dist/library/int-infer.js +10 -7
  271. package/dist/library/int-infer.js.map +1 -1
  272. package/dist/library/int-infer.test.js +44 -0
  273. package/dist/library/int-infer.test.js.map +1 -1
  274. package/dist/library/prepare.js +2 -1
  275. package/dist/library/prepare.js.map +1 -1
  276. package/dist/native/sanitizer.js +3 -1
  277. package/dist/native/sanitizer.js.map +1 -1
  278. package/dist/native/toolchain.d.ts +1 -1
  279. package/dist/native/toolchain.js +26 -6
  280. package/dist/native/toolchain.js.map +1 -1
  281. package/dist/native/toolchain.test.js +53 -1
  282. package/dist/native/toolchain.test.js.map +1 -1
  283. package/package.json +20 -20
  284. package/surface-manifest.json +170 -93
@@ -1,4 +1,5 @@
1
- import { everyExprChild, everyStmtChild } from "../../ir/traverse.js";
1
+ import { pathModuleValue } from "./lower-builtin-values.js";
2
+ import { everyExprChild, everyStmtChild, transformStmtList } from "../../ir/traverse.js";
2
3
  import { RuntimeOptionalLocals } from "./runtime-optional-locals.js";
3
4
  import { sanitizeUnregisteredClassTypes } from "./sanitize-class-types.js";
4
5
  import { UnregisteredClassTypes } from "./unregistered-class-types.js";
@@ -8,7 +9,8 @@ import { bindingInContext, captureContextBinding, declareContextLocal, declareCo
8
9
  export { newFnCtx } from "./function-context.js";
9
10
  import { InternalCompilerError } from "../../errors.js";
10
11
  import { defaultAfterUndefined, lowerStaticallyUndefinedArgument } from "./optional-arguments.js";
11
- import { ClassDynamicDispatch } from "./class-dynamic-dispatch.js";
12
+ import { ClassDynamicDispatch, trackClassFieldCreation } from "./class-dynamic-dispatch.js";
13
+ import { DeferredModuleInitializers } from "./deferred-module-initializers.js";
12
14
  import { finalizeClassMethodValues } from "./class-method-values.js";
13
15
  /* AST + checker → IR.
14
16
  *
@@ -29,14 +31,14 @@ import { bindingSource } from "../binding-source.js";
29
31
  import { tsgoPath } from "../dts-paths.js";
30
32
  import * as ts from "../ts7/adapter.js";
31
33
  import { literalValues } from "../literal-values.js";
32
- import { literalUnionArm } from "../union-discriminants.js";
34
+ import { discriminantOwners, literalUnionArm } from "../union-discriminants.js";
33
35
  import { anyOpRequiresDynamicDiag, blockedBindingUseDiag, checkerPanicDiag, componentTypeDiag, isCheckerPanic, genericSignatureTypeDiag, indexSignatureTypeDiag, intersectionTypeDiag, noLoweringDiag, overloadedSignatureTypeDiag, recordShapeMismatchDiag, requiresDynamicApiDiag, requiresDynamicPackageDiag, requiresDynamicTypeDiag, unionMismatchDiag, UNSUPPORTED, unsupportedDiag, unsupportedTypeDiag, } from "../../diagnostics/diagnostic.js";
34
36
  import { arrayOf, BOOL, canAdaptDynFuncTo, canDynCheckTo, canConvertToDyn, canCrossIslandBoundary, canExitIslandToType, canMarshalTypedFuncIntoIsland, DYN, DYN_HANDLE_KINDS, F64, isDynTypedRefType, isJsonSafeType, isJsonStringifySafeType, isSupportedMapKey, isSupportedMapValue, isUndefinedArmedUnion, isUnitType, JSVAL, NULL_T, RUNTIME_ERROR_CLASSES, STRING, typeEquals, UNDEFINED_T, VOID } from "../../ir/ir.js";
35
37
  import {} from "../npm.js";
36
38
  import { provenanceActive } from "../provenance-registry.js";
37
39
  import { ambientDtsPath, canonicalBuiltinModule, cjsExportAssignmentOf, cjsExportDiscardReason, fallbackDtsPath, isCjsExportTableLiteral, isCjsJsFile, isJsSourceFile, isNodeEsmFile, isNodeTypesPath, locOf, orderedImportsOf, overridesDtsPath, npmStaticDepSf7, requireSpecOf, resolveImport, workspacePackageOfPath, } from "../program.js";
38
40
  import { containsRecord, containsUnion, describeComponentBlocker, describeRecordMemberBlocker, formatIrType, ISLAND_AMBIENT_TYPES, isUnitOnlyTsType, jsOpenObjectType, mapType, ShapeRegistry, typeKey, UnionRegistry, withUndefinedArm as withUndefinedArmCanonical, } from "../type-mapper.js";
39
- 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";
40
42
  import { splitFiles, collectProgram, collectNpmImports, collectJsonImports, moduleArtifacts, collectGlobals, declSymbolOf, defaultExportSymbolOf, lowerFileInit, lowerDefaultExport, buildMain, appendDynamicImportModules, appendForkModules } from "./lower-modules.js";
41
43
  import { prepareCjsModuleGraph } from "./lower-node-module.js";
42
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";
@@ -50,14 +52,14 @@ import { lowerRegexMethodCall, lowerStringMethodCall } from "./containers/string
50
52
  import { lowerStreamModuleCall } from "./lower-stream.js";
51
53
  import { lowerEmitOverrideSpec } from "./lower-event-emitter.js";
52
54
  import { builtinImportOf, createRequireBindingDecl, createRequireNamespaceDecl, createRequireProgramModuleOf, createRequireSpecOf, stripTypeCasts, lowerBuiltinModuleCall, lowerNodeModuleCall, lowerTimersPromisesSetInterval, lowerFsToUnixTimestampCall, lowerFsLadderCall, lowerChildArgsArg, lowerSpawnSyncCall, lowerSpawnCall, lowerExecFileCall, lowerExecSyncCall, recordToEnvPairs, lowerJsonMethodCall, fencedBuiltinImportOf, lowerCryptoComposedCall, lowerUrlMethodCall, lowerSearchParamsMethodCall, lowerStatsMethodCall, lowerChildMethodCall, lowerAtomicsCall, lowerBuiltinExtraProperty, registerPromisifiedBuiltinDecl, 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, lowerCryptoModuleCall, lowerFsConstantsProperty, lowerBuiltinConstantsProperty, builtinConstantBindingOf, builtinConstantsDestructureDecl, lowerProcessStreamProperty, lowerStringStaticCall, lowerStringLastIndexOfCall, lowerPromiseStaticCall } from "./lower-builtins.js";
53
- import { fenceFetchObjectAssignment, fenceFetchObjectBinding, fenceStaticAbortControllerMemberRead, fenceStaticHeadersIteration, fenceStaticHeadersMember, fenceStaticReadableStreamMember, fenceStaticResponseMember, fenceUnsupportedFetchConstructorMember, isIslandExpr, islandFuncValueFence, islandRegexpOf, jsvalIn, requireDynamicApi, islandGlobalFnOf, lowerAbortControllerNew, lowerDynamicHeadersIteratorCall, lowerDynamicHeadersSpread, lowerDynamicImportCall, lowerFetchCall, lowerFetchElementMethodCall, lowerResponseNew, lowerStaticFetchCompanionCall, lowerStaticAbortControllerCall, lowerStaticAbortSignalListenerCall, lowerStaticReadableStreamCancelCall, lowerStaticReadableStreamControllerCall, lowerStaticReadableStreamNew, lowerStaticReadableStreamReaderCall, lowerStaticResponseCall, lowerIslandMethodCall, lowerMathProperty, npmPackageOf, npmMemberFence, npmPackageOfSymbol } from "./lower-island.js";
55
+ import { fenceFetchObjectAssignment, fenceFetchObjectBinding, fenceStaticAbortControllerMemberRead, fenceStaticHeadersIteration, fenceStaticHeadersMember, fenceStaticReadableStreamMember, fenceStaticResponseMember, fenceUnsupportedFetchConstructorMember, isIslandExpr, islandFuncValueFence, islandRegexpOf, jsvalIn, requireDynamicApi, islandGlobalFnOf, lowerAbortControllerNew, lowerDynamicHeadersIteratorCall, lowerDynamicHeadersSpread, lowerDynamicImportCall, lowerFetchCall, lowerFetchElementMethodCall, lowerResponseNew, lowerFetchWebNew, lowerStaticFetchCompanionCall, lowerStaticAbortControllerCall, lowerStaticAbortSignalListenerCall, lowerStaticReadableStreamCancelCall, lowerStaticReadableStreamControllerCall, lowerStaticReadableStreamNew, lowerStaticReadableStreamReaderCall, lowerStaticResponseCall, lowerIslandMethodCall, lowerMathProperty, npmPackageOf, npmMemberFence, npmPackageOfSymbol } from "./lower-island.js";
54
56
  import { lowerHttpHeadersElement, lowerNetModuleCall, lowerServerMethodCall, lowerServerProperty, lowerTlsRootCertificates } from "./lower-server.js";
55
57
  import { lowerDgramDnsModuleCall, lowerDgramMethodCall } from "./lower-dgram.js";
56
58
  import { lowerNodeTestModuleCall, lowerTestDirectCall, lowerTestMethodCall, lowerTestCtxProperty } from "./lower-test.js";
57
59
  import { lowerAssertModuleCall, lowerAssertDirectCall } from "./lower-assert.js";
58
60
  import { lowerUtilModuleCall } from "./lower-inspect.js";
59
61
  import { lowerComptime, comptimeBakeable, rejectComptimeCaptures, comptimeValueToIr } from "./lower-comptime.js";
60
- 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";
61
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";
62
64
  import { finishOptionalChain, isOptionalChainTail, lowerOptionalChain } from "./expressions/optional-chains.js";
63
65
  import { foldedStringKeyOf, lowerDynObjectLiteral, lowerObjectLiteral, lowerShorthandValue, rejectThisInObjectMethod } from "./expressions/object-literals.js";
@@ -514,6 +516,14 @@ export function dynFallbackType(lowerer, node, t) {
514
516
  if (!isJsSourceFile(node.getSourceFile())) {
515
517
  if (t.flags & ts.TypeFlags.Any)
516
518
  return DYN;
519
+ const symbol = t.getSymbol();
520
+ const args = symbol && lowerer.isStdlibSymbol(symbol) ? lowerer.checker.getTypeArguments(t) : [];
521
+ if (symbol?.name === "Promise" && args[0] && args[0].flags & ts.TypeFlags.Any)
522
+ return jsFallbackPromiseType(lowerer, t);
523
+ if (symbol && ["Generator", "AsyncGenerator", "IterableIterator"].includes(symbol.name) && args.some((arg) => arg.flags & ts.TypeFlags.Any))
524
+ return jsFallbackGeneratorType(lowerer, t);
525
+ if (lowerer.checker.isArrayType(t) && ((lowerer.checker.getTypeArguments(t)[0]?.flags ?? 0) & ts.TypeFlags.Any) !== 0)
526
+ return DYN;
517
527
  // TS single-call-signature function types: per-piece fallback, but
518
528
  // ONLY `any` pieces fall to dyn — any other unmappable piece keeps
519
529
  // the whole type's own fence.
@@ -742,18 +752,34 @@ function anyPiecedFuncType(lowerer, node, t) {
742
752
  return null;
743
753
  return { kind: "func", params, ret };
744
754
  }
745
- /** The best-effort JS `Function.prototype.name` of an expression flowing
746
- * into a dyn slot (the boxed function kind's inspect/error name):
747
- * identifier and property reads answer the referenced NAME (a
748
- * REFERENCE-SITE approximation of JS's creation-site naming — an aliased
749
- * 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
750
758
  * their own name, anonymous function/arrow expressions their
751
759
  * NamedEvaluation home (a variable initializer or property assignment).
752
760
  * Null when nothing names the value (the box stays anonymous). */
753
- export function jsFuncNameOf(node) {
761
+ export function jsFuncNameOf(node, lowerer) {
754
762
  let n = node;
755
763
  while (ts.isParenthesizedExpression(n))
756
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
+ }
757
783
  if (ts.isIdentifier(n))
758
784
  return n.text;
759
785
  if (ts.isPropertyAccessExpression(n))
@@ -765,6 +791,9 @@ export function jsFuncNameOf(node) {
765
791
  if (p && ts.isVariableDeclaration(p) && p.initializer === n && ts.isIdentifier(p.name)) {
766
792
  return p.name.text;
767
793
  }
794
+ if (p && ts.isBindingElement(p) && p.initializer === n && ts.isIdentifier(p.name)) {
795
+ return p.name.text;
796
+ }
768
797
  if (p && ts.isPropertyAssignment(p) && p.initializer === n && ts.isIdentifier(p.name)) {
769
798
  return p.name.text;
770
799
  }
@@ -799,6 +828,9 @@ export class Lowerer {
799
828
  /** Per-symbol result of the never-reassigned file scan
800
829
  * (bindingNeverReassigned — object-literal generic-method receivers). */
801
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();
802
834
  /** TRAP bindings: declarations whose initializer provably throws before
803
835
  * producing a value (its chain roots at an ambient-undefined name —
804
836
  * ambientUndefVarRootOf). Module init unwinds at the declaration, so no
@@ -1078,7 +1110,7 @@ export class Lowerer {
1078
1110
  // the initializer cannot fall back to a narrowing adapter.
1079
1111
  if (ts.isIdentifier(node) && fallback?.kind === "func") {
1080
1112
  const decl = this.checker.valueDeclarationOf(symbol);
1081
- if (decl && ts.isVariableDeclaration(decl) && decl.initializer) {
1113
+ if (decl && ts.isVariableDeclaration(decl) && !decl.type && !hasJsTypeAnnotation(decl) && decl.initializer) {
1082
1114
  let init = decl.initializer;
1083
1115
  while (ts.isParenthesizedExpression(init))
1084
1116
  init = init.expression;
@@ -1112,14 +1144,14 @@ export class Lowerer {
1112
1144
  }
1113
1145
  /** Recover the original optional union when a checked single-arm helper
1114
1146
  * was installed before a strict property consumer could name its member.
1115
- * Recovery is limited to array element reads and storage roots marked by
1116
- * 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
1117
1149
  * checked-narrow behavior. */
1118
1150
  runtimeOptionalSourceValue(node, value) {
1119
1151
  let origin = node;
1120
1152
  while (ts.isParenthesizedExpression(origin))
1121
1153
  origin = origin.expression;
1122
- let optionalOrigin = ts.isElementAccessExpression(origin);
1154
+ let optionalOrigin = ts.isElementAccessExpression(origin) || ts.isPropertyAccessExpression(origin);
1123
1155
  if (ts.isIdentifier(origin)) {
1124
1156
  const local = this.resolveLocal(origin);
1125
1157
  const root = local ? this.runtimeOptionalRootOf(local) : null;
@@ -1131,6 +1163,10 @@ export class Lowerer {
1131
1163
  }
1132
1164
  if (!optionalOrigin)
1133
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;
1134
1170
  let source = value;
1135
1171
  if (value.kind === "call" &&
1136
1172
  this.checkedNarrowHelpers.has(value.callee) &&
@@ -1331,6 +1367,17 @@ export class Lowerer {
1331
1367
  /** Union re-tag helpers (%union.retag.N), interned per (from, to)
1332
1368
  * unionId pair — see unionRetagHelper. */
1333
1369
  retagHelpers = new Map();
1370
+ /** Copy-only routes depend on the two union contracts and discriminator
1371
+ * layouts, without recursive width assumptions or evolving class members. */
1372
+ copyRetagHelpers = new Map();
1373
+ unionLiteralOwners = new Map();
1374
+ strippedUndefinedArms = new Map();
1375
+ addedUndefinedArms = new Map();
1376
+ stdlibSymbols = new Map();
1377
+ /** Method adapter names are owned by class-method-values. Looking them
1378
+ * up must not scan and retain every unrelated lifted function. */
1379
+ classMethodValueHelpers = new Set();
1380
+ classMethodValueSelections = new Map();
1334
1381
  /** Callee names of every interned coercion helper whose CALL mints a
1335
1382
  * FRESH closure per evaluation (%fn.width.*, %fn.adapt.*,
1336
1383
  * %fnval.spawnres.*). Registered at the mint site — NOT recovered by
@@ -1415,12 +1462,21 @@ export class Lowerer {
1415
1462
  /** Keyed by program-wide qualified class name (what IR object types carry). */
1416
1463
  classes = new Map();
1417
1464
  classBySymbol = new Map();
1465
+ /** Named method slots observed before class collection need a callable
1466
+ * ABI and shared prototype descriptors instead of call-site specialization. */
1467
+ prototypeMethodAccesses = new Map();
1418
1468
  /** Inferred JS methods participating in an override chain keep a vtable
1419
1469
  * ABI instead of call-site specialization. Filled before class collection. */
1420
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();
1421
1474
  /** Largest fixed argument list below a JS method, discovered before any
1422
1475
  * base vtable signature is collected. Unused checked slots carry undefined. */
1423
1476
  virtualJsMethodArity = new Map();
1477
+ checkedVirtualJsMethods = new Set();
1478
+ checkedVirtualJsAccessors = new Set();
1479
+ checkedVirtualJsValueReturns = new Set();
1424
1480
  /** The class whose members are lowering — `super` binds lexically to it
1425
1481
  * (arrows inside methods lower within this window, so they see it too). */
1426
1482
  currentClass = null;
@@ -1559,6 +1615,7 @@ export class Lowerer {
1559
1615
  * a reference to a lowerable body reports its name here — recorded even
1560
1616
  * when the enclosing statement later poisons. */
1561
1617
  onEdge = null;
1618
+ deferredModuleInitializers = null;
1562
1619
  // Stack of function contexts (bottom = the function being declared at
1563
1620
  // top level, top = the innermost nested function currently lowering).
1564
1621
  fnStack = [];
@@ -1566,7 +1623,10 @@ export class Lowerer {
1566
1623
  /** One Error-method helper belongs to this lowering session. Its cached
1567
1624
  * dispatch revision needs no weak-key identity or process-global state. */
1568
1625
  errorMethodDispatchRevision = null;
1626
+ errorPropertyDispatchRevision = null;
1569
1627
  lambdaCounter = 0;
1628
+ preparedClassFactories = new Map();
1629
+ preparingClassFactories = new Set();
1570
1630
  /** Statement lists currently mid-lowering, innermost last: the forward-
1571
1631
  * capture machinery needs to know which later statements of an OPEN list
1572
1632
  * a symbol's declaration sits in, which scope frame list-level declarations
@@ -1594,6 +1654,15 @@ export class Lowerer {
1594
1654
  * is assembled directly. The configured reachable set remains null so
1595
1655
  * demand-driven instance lowering keeps its existing gates. */
1596
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
+ }
1597
1666
  /** Coverage remainder mode: the reachability gate inverts (see wantBody)
1598
1667
  * and no module is built. */
1599
1668
  remainder;
@@ -1703,6 +1772,27 @@ export class Lowerer {
1703
1772
  ? { kind: "object", className: this.mixinTypeContext.className }
1704
1773
  : null,
1705
1774
  localClassInstance: (decl) => {
1775
+ // Computed heritage can close over parameters of its factory.
1776
+ // A speculative checker query outside that factory must not lower
1777
+ // the extends expression in the caller's lexical scope.
1778
+ if (!this.classes.has(this.classNamer(decl)) && !this.collectingExprClasses.has(decl) &&
1779
+ decl.heritageClauses?.some((clause) => clause.token === ts.SyntaxKind.ExtendsKeyword && clause.types.some((base) => {
1780
+ const expression = base.expression;
1781
+ if (ts.isCallExpression(expression))
1782
+ return true;
1783
+ if (ts.isIdentifier(expression) && this.isStdlibGlobal(expression, expression.text))
1784
+ return false;
1785
+ const symbol = this.checker.getSymbolAtLocation(ts.isPropertyAccessExpression(expression) ? expression.name : expression);
1786
+ const resolved = symbol && symbol.flags & ts.SymbolFlags.Alias ? this.checker.getAliasedSymbol(symbol) : symbol;
1787
+ if (ts.isPropertyAccessExpression(expression) && this.isStdlibGlobal(expression.expression, "globalThis") &&
1788
+ this.builtinErrorInfoOf(resolved))
1789
+ return false;
1790
+ if (resolved && this.classBySymbol.has(resolved))
1791
+ return false;
1792
+ const mapped = this.mapTypeOf(this.typeOf(expression));
1793
+ return mapped?.kind !== "classval" || !this.classes.has(mapped.className);
1794
+ })))
1795
+ return null;
1706
1796
  for (let parent = decl.parent; parent && !ts.isSourceFile(parent); parent = parent.parent) {
1707
1797
  if (!ts.isFunctionDeclaration(parent) && !ts.isFunctionExpression(parent) &&
1708
1798
  !ts.isArrowFunction(parent) && !ts.isMethodDeclaration(parent))
@@ -2266,7 +2356,7 @@ export class Lowerer {
2266
2356
  return null;
2267
2357
  const directSpec = requireSpecOf(decl.initializer);
2268
2358
  if (directSpec !== null) {
2269
- return resolveImport(this.program, decl.getSourceFile(), directSpec) ??
2359
+ return resolveImport(this.program, decl.getSourceFile(), directSpec, "require") ??
2270
2360
  npmStaticDepSf7(this.program, decl.getSourceFile(), directSpec, "require");
2271
2361
  }
2272
2362
  return createRequireProgramModuleOf(this, decl.initializer)?.dep ?? null;
@@ -2419,8 +2509,11 @@ export class Lowerer {
2419
2509
  if (!symbol)
2420
2510
  return null;
2421
2511
  const g = this.globalsBySymbol.get(symbol);
2422
- if (g)
2512
+ if (g) {
2513
+ if (g.type.kind === "func")
2514
+ g.type = this.runtimeOptionalBindingType(ident, g.type);
2423
2515
  return g;
2516
+ }
2424
2517
  for (const d of this.checker.declarationsOf(symbol)) {
2425
2518
  const byDecl = this.globalsByDeclNode.get(d);
2426
2519
  if (byDecl)
@@ -2586,7 +2679,7 @@ export class Lowerer {
2586
2679
  // Without the guarded %init call at this position
2587
2680
  // those globals stay uninitialized: the dep's module body would never
2588
2681
  // run.
2589
- const dep = resolveImport(this.program, node.getSourceFile(), spec) ??
2682
+ const dep = resolveImport(this.program, node.getSourceFile(), spec, "require") ??
2590
2683
  npmStaticDepSf7(this.program, node.getSourceFile(), spec, "require");
2591
2684
  if (!dep || dep.fileName.endsWith(".json"))
2592
2685
  return null;
@@ -2665,6 +2758,14 @@ export class Lowerer {
2665
2758
  return null;
2666
2759
  return s.flags & ts.SymbolFlags.Alias ? this.checker.getAliasedSymbol(s) : s;
2667
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
+ };
2668
2769
  const functionDeclBySymbol = new Map();
2669
2770
  const signatureBySymbol = new Map();
2670
2771
  const methodFamilies = new Map();
@@ -2818,9 +2919,11 @@ export class Lowerer {
2818
2919
  }
2819
2920
  if (ts.isBinaryExpression(e)) {
2820
2921
  const op = e.operatorToken.kind;
2821
- if (op === ts.SyntaxKind.AmpersandAmpersandToken ||
2822
- op === ts.SyntaxKind.BarBarToken ||
2823
- 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)
2824
2927
  return mayBeOptional(e.left) || mayBeOptional(e.right);
2825
2928
  }
2826
2929
  if (ts.isPropertyAccessExpression(e) && ts.isIdentifier(e.expression)) {
@@ -2946,6 +3049,29 @@ export class Lowerer {
2946
3049
  found = true;
2947
3050
  return found;
2948
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
+ }
2949
3075
  const promoteHofCallback = (callback, parameterIndices, seen = new Set()) => {
2950
3076
  let changed = false;
2951
3077
  const checkerTypeContainsTypeParameter = (type) => {
@@ -3383,6 +3509,23 @@ export class Lowerer {
3383
3509
  for (const [symbol, decl] of functionDeclBySymbol)
3384
3510
  if (scanReturns(symbol, decl))
3385
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
+ }
3386
3529
  // Every implementation of a virtual slot must retain the same ABI,
3387
3530
  // including when just one body forwards an omitted parameter.
3388
3531
  for (const family of optionalMethodFamilies) {
@@ -3427,6 +3570,14 @@ export class Lowerer {
3427
3570
  this.runtimeOptionalFunctionReturns.set(decl, arithmetic);
3428
3571
  }
3429
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
+ }
3430
3581
  for (const sf of sourceFiles) {
3431
3582
  ts.walkPreorder(sf, (node) => {
3432
3583
  if (!ts.isVariableDeclaration(node) || !ts.isIdentifier(node.name))
@@ -3434,6 +3585,23 @@ export class Lowerer {
3434
3585
  const symbol = symbolOf(node.name);
3435
3586
  if (!symbol)
3436
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
+ }
3437
3605
  const fields = optionalFields.get(symbol);
3438
3606
  if (!dynamicObjectEntryRows.has(symbol) && !optionalSymbols.has(symbol) && !fields)
3439
3607
  return;
@@ -3444,7 +3612,7 @@ export class Lowerer {
3444
3612
  if (!dynamicObjectEntryRows.has(symbol) && optionalSymbols.has(symbol))
3445
3613
  promoted = addUndefined(promoted);
3446
3614
  if (promoted.kind === "func" && node.initializer && ts.isIdentifier(node.initializer)) {
3447
- const sourceSig = this.fnSigOf(node.initializer);
3615
+ const sourceSig = signatureOf(node.initializer);
3448
3616
  if (sourceSig) {
3449
3617
  promoted = {
3450
3618
  ...promoted,
@@ -3644,6 +3812,7 @@ export class Lowerer {
3644
3812
  * and the retained reachability worklist. */
3645
3813
  finishModule(functions) {
3646
3814
  finalizeClassMethodValues(this, functions);
3815
+ trackClassFieldCreation(this, functions);
3647
3816
  // Globals typed by a class that never REGISTERED (a JS class whose
3648
3817
  // collection fenced — Symbol-keyed fields, an unsupported base): the
3649
3818
  // declaration statement and every use compiled to runtime fences, but
@@ -3814,6 +3983,7 @@ export class Lowerer {
3814
3983
  * body; both fire edges through the same hooks and are not units
3815
3984
  * themselves. */
3816
3985
  emitReachable(extraRoots) {
3986
+ this.deferredModuleInitializers = new DeferredModuleInitializers();
3817
3987
  const parts = this.splitFiles();
3818
3988
  // Direct lowering callers do not necessarily run program preflight.
3819
3989
  // Establish the same managed header/top-level batch here before
@@ -3832,6 +4002,8 @@ export class Lowerer {
3832
4002
  // before collectProgram visits them one by one; reached body lowering
3833
4003
  // will reuse the same answers later.
3834
4004
  this.prefetchClassCollection(parts.flatMap((fp) => fp.classDecls));
4005
+ const collectionEdges = new Set();
4006
+ this.onEdge = (name) => { collectionEdges.add(name); };
3835
4007
  this.collectProgram(parts);
3836
4008
  this.analyzeRuntimeOptionalArrayReads(parts);
3837
4009
  // Decorated classes analyze post-collection here too: the %init seeds
@@ -3894,13 +4066,13 @@ export class Lowerer {
3894
4066
  units.set(`%${cName}.constructor`, {
3895
4067
  order: unitOrder++,
3896
4068
  roots: classCtorRoots(info),
3897
- lower: () => this.lowerClassCtor(info),
4069
+ lower: () => info.localClass && !info.localClass.ready ? null : this.lowerClassCtor(info),
3898
4070
  });
3899
4071
  for (const { mName, member } of this.classMethodMembers(info)) {
3900
4072
  units.set(`%${cName}.${mName}`, {
3901
4073
  order: unitOrder++,
3902
4074
  roots: functionRoots(member),
3903
- lower: () => this.lowerClassMethodMember(info, member),
4075
+ lower: () => info.localClass && !info.localClass.ready ? null : this.lowerClassMethodMember(info, member),
3904
4076
  });
3905
4077
  }
3906
4078
  for (const prop of info.throwingSetters) {
@@ -3978,6 +4150,7 @@ export class Lowerer {
3978
4150
  return owner;
3979
4151
  };
3980
4152
  const reachable = new Set();
4153
+ this.constructedClasses = new Set();
3981
4154
  const queue = [];
3982
4155
  const loweredUnits = new Map();
3983
4156
  const initFunctions = [];
@@ -3988,6 +4161,12 @@ export class Lowerer {
3988
4161
  reachable.add(name);
3989
4162
  if (units.has(name))
3990
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
+ }
3991
4170
  };
3992
4171
  // Class EXPRESSIONS collect while init bodies lower (below): their
3993
4172
  // member units register the moment collection finishes — before any
@@ -3996,11 +4175,13 @@ export class Lowerer {
3996
4175
  const cName = info.def.name;
3997
4176
  const register = (name, roots, lower) => {
3998
4177
  units.set(name, { order: unitOrder++, roots, lower });
4178
+ if (reachable.has(name))
4179
+ queue.push(name);
3999
4180
  metadataPriority.set(name, [3, expressionMetadataOrder++]);
4000
4181
  };
4001
- register(`%${cName}.constructor`, classCtorRoots(info), () => this.lowerClassCtor(info));
4182
+ register(`%${cName}.constructor`, classCtorRoots(info), () => info.localClass && !info.localClass.ready ? null : this.lowerClassCtor(info));
4002
4183
  for (const { mName, member } of this.classMethodMembers(info)) {
4003
- register(`%${cName}.${mName}`, functionRoots(member), () => this.lowerClassMethodMember(info, member));
4184
+ register(`%${cName}.${mName}`, functionRoots(member), () => info.localClass && !info.localClass.ready ? null : this.lowerClassMethodMember(info, member));
4004
4185
  }
4005
4186
  if (info.staticMethods)
4006
4187
  for (const [name, entry] of info.staticMethods) {
@@ -4010,6 +4191,8 @@ export class Lowerer {
4010
4191
  register(`%${cName}.set:${prop}`, [], () => this.throwingSetterFn(info, prop));
4011
4192
  }
4012
4193
  };
4194
+ for (const name of collectionEdges)
4195
+ this.onEdge(name);
4013
4196
  // Generic instances queued by the bodies above lower here (an instance
4014
4197
  // body fires edges of its own and can queue further instances of
4015
4198
  // either kind — function instances and class instantiations drain to
@@ -4134,10 +4317,13 @@ export class Lowerer {
4134
4317
  const classDispatch = new ClassDynamicDispatch(extraRoots !== undefined);
4135
4318
  for (;;) {
4136
4319
  drainInstances();
4320
+ const initializerChanged = this.deferredModuleInitializers.process(this, [
4321
+ ...loweredUnits.values(), ...initFunctions, ...instanceFunctions, ...this.liftedFns, ...this.implicitFns,
4322
+ ]);
4137
4323
  const dispatchChanged = classDispatch.process(this, [
4138
4324
  ...loweredUnits.values(), ...initFunctions, ...instanceFunctions, ...this.liftedFns, ...this.implicitFns,
4139
4325
  ]);
4140
- if (queue.length === 0 && !dispatchChanged)
4326
+ if (queue.length === 0 && !dispatchChanged && !initializerChanged)
4141
4327
  break;
4142
4328
  drainUnits();
4143
4329
  this.restoreGenericInstanceOrder(instLowered);
@@ -4160,6 +4346,20 @@ export class Lowerer {
4160
4346
  ...this.liftedFns,
4161
4347
  ...this.implicitFns,
4162
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
+ } });
4163
4363
  this.reachableForArtifacts = reachable;
4164
4364
  return { reachable, result: this.finishModule(functions) };
4165
4365
  }
@@ -4177,12 +4377,17 @@ export class Lowerer {
4177
4377
  noteVirtualEdge(info, method) {
4178
4378
  if (!this.onEdge)
4179
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
+ }
4180
4385
  const above = this.findMethodOn(info, method);
4181
4386
  if (above)
4182
4387
  this.noteEdge(`%${above.declarer.def.name}.${method}`);
4183
4388
  const below = (c) => {
4184
4389
  for (const s of c.subclasses) {
4185
- if (s.methods.has(method))
4390
+ if (this.classCanBeConstructed(s) && s.methods.has(method))
4186
4391
  this.noteEdge(`%${s.def.name}.${method}`);
4187
4392
  below(s);
4188
4393
  }
@@ -4477,7 +4682,7 @@ export class Lowerer {
4477
4682
  Segmenter: intlHint,
4478
4683
  DisplayNames: intlHint,
4479
4684
  TextEncoder: "TextEncoder instances support encode(string) and encode(); other codec operations require a dedicated lowering",
4480
- TextDecoder: "TextDecoder instances support recognized literal labels with default options and whole-buffer decode(Uint8Array); runtime labels and options remain unsupported",
4685
+ TextDecoder: "TextDecoder instances support recognized labels, fatal/ignoreBOM option literals, and streaming UTF-8/UTF-16/single-byte decode; runtime option objects remain unsupported",
4481
4686
  };
4482
4687
  this.pushDiag(noLoweringDiag(this.checker.typeToString(type), locOf(node), typeHints[stdlibOwnSym?.name ?? ""]));
4483
4688
  throw new PoisonError();
@@ -4533,6 +4738,22 @@ export class Lowerer {
4533
4738
  return fenceStaticReadableStreamMember(this, access, use);
4534
4739
  }
4535
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
+ }
4751
+ // A checked JS method receives its actual call-site receiver. Its
4752
+ // declaration's inferred class type must not turn property reads back
4753
+ // into native field loads when the method is borrowed by another object.
4754
+ if (node.kind === ts.SyntaxKind.ThisKeyword && isJsSourceFile(node.getSourceFile()) &&
4755
+ this.fnStack.length > 0 && this.resolveThis()?.type.kind === "dyn")
4756
+ return this.checker.getUnknownType();
4536
4757
  // Inside an optional-chain body the guarded receiver is typed by its
4537
4758
  // NON-NULLISH type (the chain's tag test proved it), so every
4538
4759
  // receiver-kind check downstream sees the narrowed arm.
@@ -4577,8 +4798,15 @@ export class Lowerer {
4577
4798
  // A checked value can contain any runtime kind. A checker-proven
4578
4799
  // branch narrow therefore cannot contradict this specialization;
4579
4800
  // reads still validate the payload through maybeNarrow.
4580
- if (boundIr.kind === "dyn")
4581
- 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
+ }
4582
4810
  // A union binding narrowed to one of its arms (typeof/equality
4583
4811
  // guards over string|number bindings) — the narrow is truth.
4584
4812
  if (boundIr.kind === "union") {
@@ -4887,8 +5115,20 @@ export class Lowerer {
4887
5115
  * this is THE tag for that (union, arm) pair program-wide — every wrap,
4888
5116
  * narrow, and tag test agrees by construction. */
4889
5117
  armTag(unionId, arm) {
5118
+ return this.unions.armTag(unionId, arm);
5119
+ }
5120
+ /** Literal ownership depends only on the union contract and record layouts.
5121
+ * Recheck it when recursive placeholders close, not for every literal. */
5122
+ literalUnionArm(unionId, values) {
4890
5123
  const def = this.unions.get(unionId);
4891
- return def ? def.arms.findIndex((a) => typeEquals(a, arm)) : -1;
5124
+ if (!def || values.length === 0)
5125
+ return null;
5126
+ let cached = this.unionLiteralOwners.get(unionId);
5127
+ if (!cached || cached.shapes !== this.shapes.revision || cached.unions !== this.unions.revision) {
5128
+ cached = { owners: discriminantOwners(def, (id) => this.shapes.get(id)), shapes: this.shapes.revision, unions: this.unions.revision };
5129
+ this.unionLiteralOwners.set(unionId, cached);
5130
+ }
5131
+ return literalUnionArm(def, values, (id) => this.shapes.get(id), cached.owners);
4892
5132
  }
4893
5133
  /** Implicit union construction. Wherever a value flows into a typed slot
4894
5134
  * (initializer, assignment, call argument, return, field write, record
@@ -4991,7 +5231,14 @@ export class Lowerer {
4991
5231
  // undefined/null literals store the dyn unit values. Types outside the
4992
5232
  // dyn's domain (bytes, classes, Maps, ...) fall through to
4993
5233
  // requireExactShape's SC1101 fence.
4994
- // 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
+ }
4995
5242
  // Promise<never> return holding a `return Promise.reject(value)` the
4996
5243
  // dyn arm typed promise<dyn>): awaiting through the slot ignores the
4997
5244
  // fulfillment payload (scr_await_void) and rejections flow untyped,
@@ -5009,23 +5256,22 @@ export class Lowerer {
5009
5256
  return { kind: "seqExpr", stmts: [{ kind: "exprStmt", expr, loc: expr.loc }],
5010
5257
  result: dynUndefinedExpr(expr.loc), type: DYN, loc: expr.loc };
5011
5258
  }
5012
- // An error-HIERARCHY object (builtin subclass or user `extends
5013
- // Error` class) upcasts to the %Error root first — the caughtToDyn
5014
- // encoding (scr_dyn_from_error) carries name/message/code and the
5015
- // runtime CACHES the identity edge, so `instanceof TypeError` on
5016
- // the dyn side still answers exactly (dyn.errInstanceof). Only the
5017
- // root spelling was convertible before; the harness passes typed
5018
- // errors into untyped helpers constantly.
5259
+ // Preserve the concrete class so checked property/method dispatch
5260
+ // discovers user Error subclasses. Runtime boxing selects the live
5261
+ // view by vtable even when an error first crosses through its base.
5019
5262
  if (expr.type.kind === "object" && this.errorHierarchyClassOf(expr.type.className)) {
5020
5263
  return {
5021
5264
  kind: "dynFrom",
5022
- value: this.upcastTo(expr, "%Error"),
5265
+ value: expr,
5023
5266
  type: DYN,
5024
5267
  loc: expr.loc,
5025
5268
  };
5026
5269
  }
5027
5270
  if (expr.kind === "unitLit" || this.dynConvertible(expr.type)) {
5028
- return { kind: "dynFrom", value: expr, type: DYN, loc: expr.loc };
5271
+ const shape = expr.type.kind === "record" ? this.shapes.get(expr.type.shapeId) : undefined;
5272
+ const liveRef = expr.type.kind === "array" || !!shape && (shape.fields.length > 0 || shape.indexValue !== undefined);
5273
+ return { kind: "dynFrom", value: expr, type: DYN, loc: expr.loc,
5274
+ ...(liveRef ? { liveRef: true } : {}) };
5029
5275
  }
5030
5276
  return expr;
5031
5277
  }
@@ -5447,6 +5693,7 @@ export class Lowerer {
5447
5693
  return;
5448
5694
  const sameFamily = (src.kind === "record" && arm.kind === "record") ||
5449
5695
  (src.kind === "array" && arm.kind === "array") ||
5696
+ (src.kind === "func" && arm.kind === "func") ||
5450
5697
  (src.kind === "object" && arm.kind === "object") ||
5451
5698
  // Tuples already lift into ordinary array slots. Consider that
5452
5699
  // same conversion when the array is an arm of a union too.
@@ -5456,9 +5703,30 @@ export class Lowerer {
5456
5703
  if (sameFamily && this.widthLiftPlan(src, arm) !== null)
5457
5704
  candidates.push({ tag: i, arm });
5458
5705
  });
5459
- if (candidates.length !== 1)
5706
+ let selected = candidates;
5707
+ if (selected.length > 1 && src.kind === "record") {
5708
+ const source = this.shapes.get(src.shapeId);
5709
+ // An inferred JS union may widen its tag while retaining variants
5710
+ // with and without a value. Prefer the unique layout whose omitted
5711
+ // fields are explicitly undefined, rather than filling an optional
5712
+ // unknown slot and making both variants look equally compatible.
5713
+ const absentOnly = selected.filter(({ arm }) => {
5714
+ if (!source || arm.kind !== "record")
5715
+ return false;
5716
+ const target = this.shapes.get(arm.shapeId);
5717
+ return target !== undefined && target.fields.every((field) => {
5718
+ if (source.fields.some((present) => present.name === field.name))
5719
+ return true;
5720
+ return isUnitType(field.type) || field.type.kind === "union" &&
5721
+ this.unions.get(field.type.unionId)?.arms.every(isUnitType) === true;
5722
+ });
5723
+ });
5724
+ if (absentOnly.length === 1)
5725
+ selected = absentOnly;
5726
+ }
5727
+ if (selected.length !== 1)
5460
5728
  return null;
5461
- return { how: "liftWrap", tag: candidates[0].tag, arm: candidates[0].arm };
5729
+ return { how: "liftWrap", tag: selected[0].tag, arm: selected[0].arm };
5462
5730
  }
5463
5731
  // A UNION source into a slot that is ONE of its arms (a width copy
5464
5732
  // whose target field narrowed — the option-table choices shape:
@@ -7100,6 +7368,10 @@ export class Lowerer {
7100
7368
  const to = this.unions.get(toId);
7101
7369
  if (!from || !to)
7102
7370
  return null;
7371
+ const request = `${fromId}:${toId}:${trappable === undefined ? "" : [...trappable].sort((a, b) => a - b).join(".")}`;
7372
+ const cached = this.copyRetagHelpers.get(request);
7373
+ if (cached && cached.shapes === this.shapes.revision && cached.unions === this.unions.revision)
7374
+ return cached.name;
7103
7375
  const plan = planUnionRetag(from, to, (id) => this.shapes.get(id), (src, dst) => this.widthLiftPlan(src, dst), trappable);
7104
7376
  if (plan === null)
7105
7377
  return null;
@@ -7111,11 +7383,17 @@ export class Lowerer {
7111
7383
  stranded.push(tag); });
7112
7384
  const key = `${fromId}:${toId}:${stranded.join(".")}`;
7113
7385
  const existing = this.retagHelpers.get(key);
7114
- if (existing)
7115
- return existing;
7116
- const name = `%union.retag.${this.retagHelpers.size}`;
7117
- this.retagHelpers.set(key, name);
7118
- this.liftedFns.push(buildUnionRetag(name, from, to, plan, loc, (lift, value, dst) => this.applyWidthLift(lift, value, dst, loc), (type) => this.fmt(type)));
7386
+ const name = existing ?? `%union.retag.${this.retagHelpers.size}`;
7387
+ if (!existing) {
7388
+ this.retagHelpers.set(key, name);
7389
+ this.liftedFns.push(buildUnionRetag(name, from, to, plan, loc, (lift, value, dst) => this.applyWidthLift(lift, value, dst, loc), (type) => this.fmt(type)));
7390
+ }
7391
+ // Width routes still revalidate on every request. Only a complete plan
7392
+ // of exact payload copies and site-proven traps can bypass planning.
7393
+ if (plan.every((arm) => arm.kind === "trap" || (arm.kind === "direct"
7394
+ ? arm.route.lift.how === "copy" : arm.routes.every((route) => route.lift.how === "copy")))) {
7395
+ this.copyRetagHelpers.set(request, { name, shapes: this.shapes.revision, unions: this.unions.revision });
7396
+ }
7119
7397
  return name;
7120
7398
  }
7121
7399
  /** Interned `%union.narrow.<n>(u)` — the CHECKED single-arm extraction
@@ -7588,7 +7866,7 @@ export class Lowerer {
7588
7866
  const property = this.checker.getPropertyOfType(this.typeOf(literal), def.discriminant.field);
7589
7867
  if (property && !(property.flags & (ts.SymbolFlags.Optional | ts.SymbolFlags.GetAccessor | ts.SymbolFlags.SetAccessor))) {
7590
7868
  const values = literalValues(this.checker.getTypeOfSymbol(property));
7591
- const arm = values && literalUnionArm(def, values, (id) => this.shapes.get(id));
7869
+ const arm = values && this.literalUnionArm(def.id, values);
7592
7870
  if (arm)
7593
7871
  expr = this.coerceInto(node, expr, arm);
7594
7872
  }
@@ -7611,7 +7889,9 @@ export class Lowerer {
7611
7889
  }
7612
7890
  }
7613
7891
  }
7614
- let e = this.coerceToExpected(expr, expected);
7892
+ let e = this.dynamic && expr.type.kind === "dyn" && expected.kind === "array" && expected.elem.kind === "jsval"
7893
+ ? { kind: "jsExit", value: this.jsvalIn(expr, node), type: expected, loc: expr.loc }
7894
+ : this.coerceToExpected(expr, expected);
7615
7895
  // Existing JavaScript arrays retain mutations and identity across checked
7616
7896
  // slots. Fresh literals have no prior identity and use checked storage
7617
7897
  // directly, so later writes can change their inferred element type.
@@ -7644,7 +7924,7 @@ export class Lowerer {
7644
7924
  // NamedEvaluation through a variable initializer) — inspect prints
7645
7925
  // [Function: name] and call errors spell it, like Node.
7646
7926
  if (e.kind === "dynFrom" && e.value.type.kind === "func" && e.fnName === undefined) {
7647
- const name = jsFuncNameOf(node);
7927
+ const name = jsFuncNameOf(node, this);
7648
7928
  if (name !== null)
7649
7929
  e = { ...e, fnName: name };
7650
7930
  }
@@ -7857,7 +8137,7 @@ export class Lowerer {
7857
8137
  const property = this.checker.getPropertyOfType(this.typeOf(node), def.discriminant.field);
7858
8138
  if (property && !(property.flags & (ts.SymbolFlags.Optional | ts.SymbolFlags.GetAccessor | ts.SymbolFlags.SetAccessor))) {
7859
8139
  const values = literalValues(this.checker.getTypeOfSymbol(property));
7860
- const arm = values && literalUnionArm(def, values, (id) => this.shapes.get(id));
8140
+ const arm = values && this.literalUnionArm(def.id, values);
7861
8141
  if (arm)
7862
8142
  return this.coerceInto(node, this.lowerObjectLiteral(node, arm), expected);
7863
8143
  }
@@ -7865,7 +8145,7 @@ export class Lowerer {
7865
8145
  }
7866
8146
  // An OBJECT LITERAL against a checked-dynamic slot in a JS file (the
7867
8147
  // getSupportInfo options argument — a dyn-ABI param), or against the
7868
- // standard RequestInit/ErrorOptions types in TypeScript: the value's world IS the
8148
+ // standard native option-bag types in TypeScript: the value's world IS the
7869
8149
  // checked-dynamic tree — build the dyn literal directly.
7870
8150
  if (expected?.kind === "dyn") {
7871
8151
  let x = node;
@@ -7885,7 +8165,8 @@ export class Lowerer {
7885
8165
  return sym?.name === name && this.isStdlibSymbol(sym);
7886
8166
  });
7887
8167
  if (ts.isObjectLiteralExpression(x)) {
7888
- if (isJsSourceFile(x.getSourceFile()) || builtinOption("RequestInit") || builtinOption("ErrorOptions")) {
8168
+ if (isJsSourceFile(x.getSourceFile()) || builtinOption("RequestInit") || builtinOption("ErrorOptions") || builtinOption("SpawnOptions") ||
8169
+ !this.mapTypeOf(this.typeOf(x))) {
7889
8170
  return lowerDynObjectLiteral(this, x);
7890
8171
  }
7891
8172
  }
@@ -7933,7 +8214,7 @@ export class Lowerer {
7933
8214
  }
7934
8215
  }
7935
8216
  let e = this.lowerExpr(node);
7936
- 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())) {
7937
8218
  // A destination that accepts undefined must retain an unchecked
7938
8219
  // read's storage value even when the checker still calls it present.
7939
8220
  e = this.runtimeOptionalSourceValue(node, e) ?? e;
@@ -7994,7 +8275,19 @@ export class Lowerer {
7994
8275
  * declared result type of an index-signature read under
7995
8276
  * noUncheckedIndexedAccess. Null when the type cannot take the arm. */
7996
8277
  withUndefinedArmOf(t) {
7997
- 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;
7998
8291
  }
7999
8292
  /** True when a static type converts to a dyn value (the dynFrom
8000
8293
  * walker's domain): JSON-safe, bytes<u8> (Uint8Array/Buffer — the checked-dynamic tree's
@@ -8096,14 +8389,17 @@ export class Lowerer {
8096
8389
  stripUndefinedArm(t) {
8097
8390
  if (t.kind !== "union")
8098
8391
  return t;
8392
+ const cached = this.strippedUndefinedArms.get(t.unionId);
8393
+ if (cached && cached.unions === this.unions.revision)
8394
+ return cached.type;
8099
8395
  const def = this.unions.get(t.unionId);
8100
- if (!def || !def.arms.some((a) => a.kind === "undefinedT"))
8396
+ if (!def || this.armTag(t.unionId, UNDEFINED_T) < 0)
8101
8397
  return t;
8102
8398
  const rest = def.arms.filter((a) => a.kind !== "undefinedT");
8103
- if (rest.length === 1)
8104
- return rest[0];
8105
8399
  // Removing an arm keeps canonical (typeKey-sorted) order.
8106
- return { kind: "union", unionId: this.unions.transform(def, rest) };
8400
+ const type = rest.length === 1 ? rest[0] : { kind: "union", unionId: this.unions.transform(def, rest) };
8401
+ this.strippedUndefinedArms.set(t.unionId, { type, unions: this.unions.revision });
8402
+ return type;
8107
8403
  }
8108
8404
  /** The interned `T | undefined` union over a non-union arm type — the ABI
8109
8405
  * type of a defaulted parameter, and the result type of lookups that may
@@ -8164,13 +8460,14 @@ export class Lowerer {
8164
8460
  * symbol reports eagerly (nothing could ever reference it). */
8165
8461
  collectDeferring(symbolOf, collect) {
8166
8462
  const sink = [];
8463
+ const previousSink = this.diagSink;
8167
8464
  this.diagSink = sink;
8168
8465
  try {
8169
8466
  collect();
8170
8467
  return null;
8171
8468
  }
8172
8469
  catch (e) {
8173
- this.diagSink = null;
8470
+ this.diagSink = previousSink;
8174
8471
  const symbol = (() => {
8175
8472
  // symbolOf queries the checker too — a second panic must not
8176
8473
  // escape the fence that is handling the first.
@@ -8203,7 +8500,7 @@ export class Lowerer {
8203
8500
  return symbol;
8204
8501
  }
8205
8502
  finally {
8206
- this.diagSink = null;
8503
+ this.diagSink = previousSink;
8207
8504
  }
8208
8505
  }
8209
8506
  /** Pushes a symbol's deferred collection diagnostics: lowering resolved
@@ -8384,6 +8681,8 @@ export class Lowerer {
8384
8681
  * BEFORE that statement (JS's order for the supported whole-initializer
8385
8682
  * positions). */
8386
8683
  pendingClassExprInits = [];
8684
+ computedClassBases = new Map();
8685
+ computedCallableBases = new Map();
8387
8686
  /** Discovery hook: registers a just-collected expression class's member
8388
8687
  * bodies as worklist units (the units map is otherwise built before
8389
8688
  * lowering starts). Null in the emit pass. */
@@ -8472,11 +8771,7 @@ export class Lowerer {
8472
8771
  // Computed method names resolve exactly like collection did
8473
8772
  // (classMemberNameOf — folded keys and the sym:iterator slot);
8474
8773
  // unresolvable ones never collected, so they skip here too.
8475
- const baseName = ts.isMethodDeclaration(fnLike)
8476
- ? classMemberNameOf(this, fnLike.name)
8477
- : ts.isIdentifier(fnLike.name) || ts.isPrivateIdentifier(fnLike.name)
8478
- ? fnLike.name.text
8479
- : null;
8774
+ const baseName = classMemberNameOf(this, fnLike.name);
8480
8775
  if (baseName === null)
8481
8776
  continue;
8482
8777
  const mName = ts.isMethodDeclaration(fnLike) ? baseName : `${ts.isGetAccessor(fnLike) ? "get" : "set"}:${baseName}`;
@@ -8847,9 +9142,7 @@ export class Lowerer {
8847
9142
  });
8848
9143
  if (resolved.error !== null) {
8849
9144
  const location = blame ?? (symbol === undefined ? undefined : this.checker.declarationsOf(symbol)[0]) ?? this.entry;
8850
- const message = resolved.error === "caught"
8851
- ? "closures capturing catch bindings (narrow into a typed local first)"
8852
- : `the binding '${resolved.origin.name}' captured through a plain nested function (the declaration has no static storage a capture can thread — bind the value through a typed const, or read it in the declaring scope)`;
9145
+ const message = `the binding '${resolved.origin.name}' captured through a plain nested function (the declaration has no static storage a capture can thread — bind the value through a typed const, or read it in the declaring scope)`;
8853
9146
  this.unsupported("SC1090", location, message);
8854
9147
  }
8855
9148
  if (resolved.local !== null)
@@ -9238,7 +9531,16 @@ export class Lowerer {
9238
9531
  return isStdlibMember(this, access);
9239
9532
  }
9240
9533
  isStdlibSymbol(symbol) {
9241
- return isStdlibSymbol(this, symbol);
9534
+ if (!symbol)
9535
+ return false;
9536
+ const cached = this.stdlibSymbols.get(symbol);
9537
+ if (cached !== undefined)
9538
+ return cached;
9539
+ // A compilation's checker declarations and library provenance are fixed.
9540
+ // Global alias and narrowing state remain outside this symbol-only cache.
9541
+ const result = isStdlibSymbol(this, symbol);
9542
+ this.stdlibSymbols.set(symbol, result);
9543
+ return result;
9242
9544
  }
9243
9545
  isStdlibGlobal(expr, name) {
9244
9546
  return isStdlibGlobal(this, expr, name);
@@ -9580,7 +9882,7 @@ export class Lowerer {
9580
9882
  const arg = this.lowerExpr(expr.arguments[0]);
9581
9883
  return { kind: "jsOp", op: "construct", args: [ctor, arg], type: JSVAL, loc };
9582
9884
  }
9583
- const builtin = lowerAbortControllerNew(this, expr) ?? lowerResponseNew(this, expr) ?? lowerStaticReadableStreamNew(this, expr);
9885
+ const builtin = lowerAbortControllerNew(this, expr) ?? lowerFetchWebNew(this, expr) ?? lowerResponseNew(this, expr) ?? lowerStaticReadableStreamNew(this, expr);
9584
9886
  return builtin ?? this.withRuntimeOptionalClassValue(expr.expression, () => lowerNew(this, expr));
9585
9887
  }
9586
9888
  lowerFieldRead(expr) {
@@ -9640,6 +9942,10 @@ export class Lowerer {
9640
9942
  * member access that IS a module in its own right (`fs.promises` — the
9641
9943
  * same object as node:fs/promises, Node's rule). Null otherwise. */
9642
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;
9643
9949
  const stored = ts.isIdentifier(expr)
9644
9950
  ? (this.peekLocal(expr)?.type ?? this.globalOf(expr)?.type)
9645
9951
  : undefined;
@@ -9862,10 +10168,10 @@ export class Lowerer {
9862
10168
  if (!expr.questionDotToken && ts.isPropertyAccessExpression(expr.expression)) {
9863
10169
  const inner = this.builtinMemberOf(expr.expression);
9864
10170
  if (inner && inner.module === "fs" && inner.member === "constants") {
9865
- const MODES = { F_OK: 0, X_OK: 1, W_OK: 2, R_OK: 4 };
10171
+ const MODES = { F_OK: 0, X_OK: 1, W_OK: 2, R_OK: 4, COPYFILE_EXCL: 1, COPYFILE_FICLONE: 2, COPYFILE_FICLONE_FORCE: 4 };
9866
10172
  const value = own(MODES, expr.name.text);
9867
10173
  if (value === undefined) {
9868
- this.noLowering(`fs.constants.${expr.name.text}`, expr, "F_OK, R_OK, W_OK, and X_OK are the lowered constants");
10174
+ this.noLowering(`fs.constants.${expr.name.text}`, expr, "F_OK, R_OK, W_OK, X_OK, and COPYFILE_* are the lowered constants");
9869
10175
  }
9870
10176
  return { kind: "numLit", value, type: F64, loc };
9871
10177
  }
@@ -9873,6 +10179,10 @@ export class Lowerer {
9873
10179
  const bi = this.builtinMemberOf(expr);
9874
10180
  if (!bi)
9875
10181
  return null;
10182
+ if ((bi.module === "path" || bi.module === "path/posix" || bi.module === "path/win32") &&
10183
+ (bi.member === "posix" || bi.member === "win32")) {
10184
+ return pathModuleValue(this, `path/${bi.member}`, loc);
10185
+ }
9876
10186
  // events.defaultMaxListeners READS the process-wide default (its
9877
10187
  // write twin routes through emitter.setDefaultMaxChk).
9878
10188
  if (bi.module === "events" && bi.member === "defaultMaxListeners") {
@@ -9908,7 +10218,7 @@ export class Lowerer {
9908
10218
  }
9909
10219
  if (bi.member === "constants" && bi.module === "fs") {
9910
10220
  // A bare `fs.constants` read (not one of the baked bits above).
9911
- this.noLowering(`fs.constants`, expr, "F_OK, R_OK, W_OK, and X_OK are the lowered constants");
10221
+ this.noLowering(`fs.constants`, expr, "F_OK, R_OK, W_OK, X_OK, and COPYFILE_* are the lowered constants");
9912
10222
  }
9913
10223
  if (builtinModuleFnOf(this, bi.module, bi.member)) {
9914
10224
  this.unsupported("SC1090", expr, `library functions as values (call '${expr.getText()}' directly)`);
@@ -9921,6 +10231,9 @@ export class Lowerer {
9921
10231
  * deliberately narrower than table membership because many table rows
9922
10232
  * are only dispatch sentinels for call-site-specific lowering. */
9923
10233
  lowerBuiltinCallableValue(bi, loc) {
10234
+ if (bi.module === "fs" && builtinModuleFnOf(this, bi.module, bi.member)?.fn === "fs.callbackCall") {
10235
+ return { kind: "libCall", fn: "fs.callbackValue", args: [{ kind: "strLit", value: bi.member, type: STRING, loc }], type: DYN, loc };
10236
+ }
9924
10237
  const fn = builtinModuleFnOf(this, bi.module, bi.member);
9925
10238
  return fn ? this.lowerNativeCallableValue(fn, `${bi.module}.${bi.member}`, loc) : null;
9926
10239
  }