@scriptc/compiler 0.0.35 → 0.1.1

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 (439) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +14 -11
  2. package/ambient/scriptc-overrides.d.ts +0 -7
  3. package/ambient/scriptc.d.ts +1 -1
  4. package/dist/backend/build-cache.d.ts +44 -0
  5. package/dist/backend/build-cache.js +241 -0
  6. package/dist/backend/build-cache.js.map +1 -0
  7. package/dist/backend/{emission/emit-async.d.ts → c/async.d.ts} +21 -30
  8. package/dist/backend/{emission/emit-async.js → c/async.js} +270 -286
  9. package/dist/backend/c/async.js.map +1 -0
  10. package/dist/backend/{emission/emitter.d.ts → c/c-emitter.d.ts} +6 -23
  11. package/dist/backend/{emission/emitter.js → c/c-emitter.js} +53 -107
  12. package/dist/backend/c/c-emitter.js.map +1 -0
  13. package/dist/backend/c/exprs.d.ts +8 -0
  14. package/dist/backend/c/exprs.js +7937 -0
  15. package/dist/backend/c/exprs.js.map +1 -0
  16. package/dist/backend/{emission/emit-island.d.ts → c/island.d.ts} +5 -5
  17. package/dist/backend/{emission/emit-island.js → c/island.js} +24 -22
  18. package/dist/backend/c/island.js.map +1 -0
  19. package/dist/backend/{emission → c}/may-throw.d.ts +1 -1
  20. package/dist/backend/{emission → c}/may-throw.js +4 -1
  21. package/dist/backend/c/may-throw.js.map +1 -0
  22. package/dist/backend/{emission/emit-shapes.d.ts → c/shapes.d.ts} +19 -19
  23. package/dist/backend/{emission/emit-shapes.js → c/shapes.js} +78 -87
  24. package/dist/backend/c/shapes.js.map +1 -0
  25. package/dist/backend/{emission/emit-stmts.d.ts → c/stmts.d.ts} +12 -12
  26. package/dist/backend/{emission/emit-stmts.js → c/stmts.js} +395 -343
  27. package/dist/backend/c/stmts.js.map +1 -0
  28. package/dist/backend/{emission/emit-types.d.ts → c/types.d.ts} +1 -1
  29. package/dist/backend/{emission/emit-types.js → c/types.js} +42 -286
  30. package/dist/backend/c/types.js.map +1 -0
  31. package/dist/backend/c/types.test.js +25 -0
  32. package/dist/backend/c/types.test.js.map +1 -0
  33. package/dist/backend/{emission/emit-walkers.d.ts → c/walkers.d.ts} +19 -41
  34. package/dist/backend/{emission/emit-walkers.js → c/walkers.js} +242 -304
  35. package/dist/backend/c/walkers.js.map +1 -0
  36. package/dist/backend/external-c.d.ts +33 -0
  37. package/dist/backend/external-c.js +51 -0
  38. package/dist/backend/external-c.js.map +1 -0
  39. package/dist/backend/ffi-callbacks.d.ts +1 -1
  40. package/dist/backend/ffi-callbacks.js +4 -3
  41. package/dist/backend/ffi-callbacks.js.map +1 -1
  42. package/dist/backend/{library-identity.d.ts → library-identity-markers.d.ts} +0 -4
  43. package/dist/backend/{library-identity.js → library-identity-markers.js} +10 -9
  44. package/dist/backend/library-identity-markers.js.map +1 -0
  45. package/dist/backend/link-plan.d.ts +37 -0
  46. package/dist/backend/link-plan.js +26 -0
  47. package/dist/backend/link-plan.js.map +1 -0
  48. package/dist/backend/linker.d.ts +22 -0
  49. package/dist/backend/linker.js +236 -0
  50. package/dist/backend/linker.js.map +1 -0
  51. package/dist/backend/llvm/blocks.d.ts +4 -0
  52. package/dist/backend/llvm/blocks.js +29 -0
  53. package/dist/backend/llvm/blocks.js.map +1 -1
  54. package/dist/backend/llvm/classes.d.ts +2 -19
  55. package/dist/backend/llvm/classes.js +20 -52
  56. package/dist/backend/llvm/classes.js.map +1 -1
  57. package/dist/backend/llvm/common.d.ts +4 -0
  58. package/dist/backend/llvm/common.js +27 -0
  59. package/dist/backend/llvm/common.js.map +1 -0
  60. package/dist/backend/llvm/dyn.d.ts +3 -8
  61. package/dist/backend/llvm/dyn.js +159 -224
  62. package/dist/backend/llvm/dyn.js.map +1 -1
  63. package/dist/backend/llvm/emitter.d.ts +4 -1
  64. package/dist/backend/llvm/emitter.js +548 -9988
  65. package/dist/backend/llvm/emitter.js.map +1 -1
  66. package/dist/backend/llvm/expr-async.d.ts +4 -0
  67. package/dist/backend/llvm/expr-async.js +726 -0
  68. package/dist/backend/llvm/expr-async.js.map +1 -0
  69. package/dist/backend/llvm/expr-bytes.d.ts +13 -0
  70. package/dist/backend/llvm/expr-bytes.js +456 -0
  71. package/dist/backend/llvm/expr-bytes.js.map +1 -0
  72. package/dist/backend/llvm/expr-callbacks.d.ts +22 -0
  73. package/dist/backend/llvm/expr-callbacks.js +520 -0
  74. package/dist/backend/llvm/expr-callbacks.js.map +1 -0
  75. package/dist/backend/llvm/expr-calls.d.ts +2 -0
  76. package/dist/backend/llvm/expr-calls.js +618 -0
  77. package/dist/backend/llvm/expr-calls.js.map +1 -0
  78. package/dist/backend/llvm/expr-containers.d.ts +25 -0
  79. package/dist/backend/llvm/expr-containers.js +637 -0
  80. package/dist/backend/llvm/expr-containers.js.map +1 -0
  81. package/dist/backend/llvm/expr-context.d.ts +255 -0
  82. package/dist/backend/llvm/expr-context.js +2 -0
  83. package/dist/backend/llvm/expr-context.js.map +1 -0
  84. package/dist/backend/llvm/expr-control.d.ts +2 -0
  85. package/dist/backend/llvm/expr-control.js +473 -0
  86. package/dist/backend/llvm/expr-control.js.map +1 -0
  87. package/dist/backend/llvm/expr-dispatch.d.ts +4 -0
  88. package/dist/backend/llvm/expr-dispatch.js +153 -0
  89. package/dist/backend/llvm/expr-dispatch.js.map +1 -0
  90. package/dist/backend/llvm/expr-dynamic.d.ts +2 -0
  91. package/dist/backend/llvm/expr-dynamic.js +810 -0
  92. package/dist/backend/llvm/expr-dynamic.js.map +1 -0
  93. package/dist/backend/llvm/expr-island.d.ts +15 -0
  94. package/dist/backend/llvm/expr-island.js +690 -0
  95. package/dist/backend/llvm/expr-island.js.map +1 -0
  96. package/dist/backend/llvm/expr-primitives.d.ts +6 -0
  97. package/dist/backend/llvm/expr-primitives.js +642 -0
  98. package/dist/backend/llvm/expr-primitives.js.map +1 -0
  99. package/dist/backend/llvm/expr-records.d.ts +9 -0
  100. package/dist/backend/llvm/expr-records.js +299 -0
  101. package/dist/backend/llvm/expr-records.js.map +1 -0
  102. package/dist/backend/llvm/expr-stream-bridges.d.ts +13 -0
  103. package/dist/backend/llvm/expr-stream-bridges.js +420 -0
  104. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -0
  105. package/dist/backend/llvm/expr-stream-callbacks.d.ts +12 -0
  106. package/dist/backend/llvm/expr-stream-callbacks.js +360 -0
  107. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -0
  108. package/dist/backend/llvm/lib-dispatch.d.ts +5 -0
  109. package/dist/backend/llvm/lib-dispatch.js +267 -0
  110. package/dist/backend/llvm/lib-dispatch.js.map +1 -0
  111. package/dist/backend/llvm/lib-filesystem.d.ts +6 -0
  112. package/dist/backend/llvm/lib-filesystem.js +594 -0
  113. package/dist/backend/llvm/lib-filesystem.js.map +1 -0
  114. package/dist/backend/llvm/lib-network.d.ts +2 -0
  115. package/dist/backend/llvm/lib-network.js +429 -0
  116. package/dist/backend/llvm/lib-network.js.map +1 -0
  117. package/dist/backend/llvm/lib-process.d.ts +5 -0
  118. package/dist/backend/llvm/lib-process.js +585 -0
  119. package/dist/backend/llvm/lib-process.js.map +1 -0
  120. package/dist/backend/llvm/lib-shared.d.ts +6 -0
  121. package/dist/backend/llvm/lib-shared.js +687 -0
  122. package/dist/backend/llvm/lib-shared.js.map +1 -0
  123. package/dist/backend/llvm/lib-stream.d.ts +2 -0
  124. package/dist/backend/llvm/lib-stream.js +470 -0
  125. package/dist/backend/llvm/lib-stream.js.map +1 -0
  126. package/dist/backend/llvm/shapes.d.ts +12 -2
  127. package/dist/backend/llvm/shapes.js +66 -307
  128. package/dist/backend/llvm/shapes.js.map +1 -1
  129. package/dist/backend/llvm/shapes.test.js +52 -0
  130. package/dist/backend/llvm/shapes.test.js.map +1 -0
  131. package/dist/backend/llvm/unsupported.d.ts +1 -1
  132. package/dist/backend/llvm/walkers.d.ts +2 -3
  133. package/dist/backend/llvm/walkers.js +195 -222
  134. package/dist/backend/llvm/walkers.js.map +1 -1
  135. package/dist/backend/native-codegen.d.ts +45 -0
  136. package/dist/backend/native-codegen.js +275 -0
  137. package/dist/backend/native-codegen.js.map +1 -0
  138. package/dist/backend/native-codegen.test.js +226 -0
  139. package/dist/backend/native-codegen.test.js.map +1 -0
  140. package/dist/backend/native-link-info.d.ts +96 -0
  141. package/dist/backend/native-link-info.js +243 -0
  142. package/dist/backend/native-link-info.js.map +1 -0
  143. package/dist/backend/native-link-info.test.d.ts +1 -0
  144. package/dist/backend/native-link-info.test.js +134 -0
  145. package/dist/backend/native-link-info.test.js.map +1 -0
  146. package/dist/backend/{cc.d.ts → native-toolchain.d.ts} +54 -34
  147. package/dist/backend/{cc.js → native-toolchain.js} +231 -810
  148. package/dist/backend/native-toolchain.js.map +1 -0
  149. package/dist/backend/native-toolchain.test.d.ts +1 -0
  150. package/dist/backend/{cc-cache.test.js → native-toolchain.test.js} +219 -7
  151. package/dist/backend/native-toolchain.test.js.map +1 -0
  152. package/dist/backend/object-localize.js +1 -1
  153. package/dist/backend/runtime-abi.d.ts +10 -0
  154. package/dist/backend/runtime-abi.js +11 -0
  155. package/dist/backend/runtime-abi.js.map +1 -0
  156. package/dist/backend/runtime-pack-targets.test.d.ts +1 -0
  157. package/dist/backend/runtime-pack-targets.test.js +54 -0
  158. package/dist/backend/runtime-pack-targets.test.js.map +1 -0
  159. package/dist/backend/runtime-pack.d.ts +112 -0
  160. package/dist/backend/runtime-pack.js +305 -0
  161. package/dist/backend/runtime-pack.js.map +1 -0
  162. package/dist/backend/runtime-pack.test.d.ts +1 -0
  163. package/dist/backend/runtime-pack.test.js +473 -0
  164. package/dist/backend/runtime-pack.test.js.map +1 -0
  165. package/dist/backend/targets.d.ts +76 -0
  166. package/dist/backend/targets.js +262 -0
  167. package/dist/backend/targets.js.map +1 -0
  168. package/dist/backend/targets.test.d.ts +1 -0
  169. package/dist/backend/targets.test.js +41 -0
  170. package/dist/backend/targets.test.js.map +1 -0
  171. package/dist/backend/vendor-archives.d.ts +41 -0
  172. package/dist/backend/vendor-archives.js +462 -0
  173. package/dist/backend/vendor-archives.js.map +1 -0
  174. package/dist/compat/fetch-profile.d.ts +0 -1
  175. package/dist/compat/fetch-profile.js +0 -1
  176. package/dist/compat/fetch-profile.js.map +1 -1
  177. package/dist/coverage/report.js +3 -3
  178. package/dist/coverage/report.js.map +1 -1
  179. package/dist/coverage/surface-manifest.js +35 -33
  180. package/dist/coverage/surface-manifest.js.map +1 -1
  181. package/dist/diagnostics/diagnostic.d.ts +11 -12
  182. package/dist/diagnostics/diagnostic.js +19 -17
  183. package/dist/diagnostics/diagnostic.js.map +1 -1
  184. package/dist/diagnostics/render.d.ts +1 -1
  185. package/dist/diagnostics/render.js +1 -1
  186. package/dist/diagnostics/render.js.map +1 -1
  187. package/dist/errors.d.ts +5 -0
  188. package/dist/errors.js +9 -0
  189. package/dist/errors.js.map +1 -0
  190. package/dist/executable/{early-cache.d.ts → executable-cache.d.ts} +2 -2
  191. package/dist/executable/{early-cache.js → executable-cache.js} +36 -98
  192. package/dist/executable/executable-cache.js.map +1 -0
  193. package/dist/executable/executable-cache.test.d.ts +1 -0
  194. package/dist/executable/{early-cache.test.js → executable-cache.test.js} +3 -3
  195. package/dist/executable/executable-cache.test.js.map +1 -0
  196. package/dist/ffi/{profile.js → ffi-manifest.js} +1 -1
  197. package/dist/ffi/ffi-manifest.js.map +1 -0
  198. package/dist/frontend/builtin-modules.d.ts +21 -0
  199. package/dist/frontend/builtin-modules.js +82 -0
  200. package/dist/frontend/builtin-modules.js.map +1 -0
  201. package/dist/frontend/cjs-lexer.d.ts +7 -0
  202. package/dist/frontend/cjs-lexer.js +15 -17
  203. package/dist/frontend/cjs-lexer.js.map +1 -1
  204. package/dist/frontend/dts-paths.d.ts +26 -0
  205. package/dist/frontend/dts-paths.js +41 -0
  206. package/dist/frontend/dts-paths.js.map +1 -0
  207. package/dist/frontend/input-tracker.d.ts +0 -2
  208. package/dist/frontend/input-tracker.js +1 -4
  209. package/dist/frontend/input-tracker.js.map +1 -1
  210. package/dist/frontend/lib-contract.d.ts +1 -5
  211. package/dist/frontend/lib-contract.js +1 -1
  212. package/dist/frontend/lib-contract.js.map +1 -1
  213. package/dist/frontend/lib-exports.d.ts +1 -1
  214. package/dist/frontend/lowering/array-values.d.ts +8 -0
  215. package/dist/frontend/lowering/array-values.js +60 -0
  216. package/dist/frontend/lowering/array-values.js.map +1 -0
  217. package/dist/frontend/lowering/call-position.d.ts +4 -0
  218. package/dist/frontend/lowering/call-position.js +7 -0
  219. package/dist/frontend/lowering/call-position.js.map +1 -0
  220. package/dist/frontend/lowering/callback-arg.d.ts +20 -0
  221. package/dist/frontend/lowering/callback-arg.js +44 -0
  222. package/dist/frontend/lowering/callback-arg.js.map +1 -0
  223. package/dist/frontend/lowering/lib-boundary.d.ts +1 -1
  224. package/dist/frontend/lowering/lib-boundary.js +34 -34
  225. package/dist/frontend/lowering/lib-boundary.js.map +1 -1
  226. package/dist/frontend/lowering/lower-array-sort.d.ts +22 -0
  227. package/dist/frontend/lowering/lower-array-sort.js +619 -0
  228. package/dist/frontend/lowering/lower-array-sort.js.map +1 -0
  229. package/dist/frontend/lowering/lower-assert.d.ts +3 -3
  230. package/dist/frontend/lowering/lower-assert.js +214 -241
  231. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  232. package/dist/frontend/lowering/lower-builtins.d.ts +74 -146
  233. package/dist/frontend/lowering/lower-builtins.js +1285 -1233
  234. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  235. package/dist/frontend/lowering/lower-calls.d.ts +59 -192
  236. package/dist/frontend/lowering/lower-calls.js +1644 -1506
  237. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  238. package/dist/frontend/lowering/lower-classes.d.ts +62 -125
  239. package/dist/frontend/lowering/lower-classes.js +832 -866
  240. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  241. package/dist/frontend/lowering/lower-comptime.d.ts +5 -12
  242. package/dist/frontend/lowering/lower-comptime.js +32 -31
  243. package/dist/frontend/lowering/lower-comptime.js.map +1 -1
  244. package/dist/frontend/lowering/lower-containers.d.ts +35 -135
  245. package/dist/frontend/lowering/lower-containers.js +1984 -2227
  246. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  247. package/dist/frontend/lowering/lower-dgram.d.ts +3 -7
  248. package/dist/frontend/lowering/lower-dgram.js +97 -111
  249. package/dist/frontend/lowering/lower-dgram.js.map +1 -1
  250. package/dist/frontend/lowering/lower-enums.d.ts +4 -4
  251. package/dist/frontend/lowering/lower-enums.js +30 -30
  252. package/dist/frontend/lowering/lower-enums.js.map +1 -1
  253. package/dist/frontend/lowering/{lower-emitter.d.ts → lower-event-emitter.d.ts} +7 -18
  254. package/dist/frontend/lowering/{lower-emitter.js → lower-event-emitter.js} +172 -174
  255. package/dist/frontend/lowering/lower-event-emitter.js.map +1 -0
  256. package/dist/frontend/lowering/lower-expando.d.ts +5 -5
  257. package/dist/frontend/lowering/lower-expando.js +40 -40
  258. package/dist/frontend/lowering/lower-expando.js.map +1 -1
  259. package/dist/frontend/lowering/lower-exprs.d.ts +60 -264
  260. package/dist/frontend/lowering/lower-exprs.js +2361 -1765
  261. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  262. package/dist/frontend/lowering/lower-generators.d.ts +6 -6
  263. package/dist/frontend/lowering/lower-generators.js +73 -72
  264. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  265. package/dist/frontend/lowering/lower-inspect.d.ts +5 -17
  266. package/dist/frontend/lowering/lower-inspect.js +273 -261
  267. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  268. package/dist/frontend/lowering/lower-island.d.ts +39 -49
  269. package/dist/frontend/lowering/lower-island.js +447 -513
  270. package/dist/frontend/lowering/lower-island.js.map +1 -1
  271. package/dist/frontend/lowering/lower-mixins.d.ts +7 -10
  272. package/dist/frontend/lowering/lower-mixins.js +85 -85
  273. package/dist/frontend/lowering/lower-mixins.js.map +1 -1
  274. package/dist/frontend/lowering/lower-modules.d.ts +12 -18
  275. package/dist/frontend/lowering/lower-modules.js +284 -283
  276. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  277. package/dist/frontend/lowering/lower-namespaces.d.ts +23 -49
  278. package/dist/frontend/lowering/lower-namespaces.js +123 -115
  279. package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
  280. package/dist/frontend/lowering/lower-server.d.ts +18 -25
  281. package/dist/frontend/lowering/lower-server.js +909 -899
  282. package/dist/frontend/lowering/lower-server.js.map +1 -1
  283. package/dist/frontend/lowering/lower-stmts.d.ts +30 -149
  284. package/dist/frontend/lowering/lower-stmts.js +1463 -1285
  285. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  286. package/dist/frontend/lowering/lower-stream.d.ts +12 -12
  287. package/dist/frontend/lowering/lower-stream.js +300 -301
  288. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  289. package/dist/frontend/lowering/lower-test.d.ts +5 -5
  290. package/dist/frontend/lowering/lower-test.js +82 -82
  291. package/dist/frontend/lowering/lower-test.js.map +1 -1
  292. package/dist/frontend/lowering/lowerer.d.ts +134 -22
  293. package/dist/frontend/lowering/lowerer.js +1277 -126
  294. package/dist/frontend/lowering/lowerer.js.map +1 -1
  295. package/dist/frontend/lowering/pairs-snapshot.d.ts +11 -0
  296. package/dist/frontend/lowering/pairs-snapshot.js +85 -0
  297. package/dist/frontend/lowering/pairs-snapshot.js.map +1 -0
  298. package/dist/frontend/lowering/static-this.d.ts +6 -0
  299. package/dist/frontend/lowering/static-this.js +24 -0
  300. package/dist/frontend/lowering/static-this.js.map +1 -0
  301. package/dist/frontend/lowering/surfaces.d.ts +24 -35
  302. package/dist/frontend/lowering/surfaces.js +78 -66
  303. package/dist/frontend/lowering/surfaces.js.map +1 -1
  304. package/dist/frontend/npm-static-rewrite.js +6 -28
  305. package/dist/frontend/npm-static-rewrite.js.map +1 -1
  306. package/dist/frontend/npm-static.d.ts +0 -10
  307. package/dist/frontend/npm-static.js +4 -7
  308. package/dist/frontend/npm-static.js.map +1 -1
  309. package/dist/frontend/npm.d.ts +0 -24
  310. package/dist/frontend/npm.js +11 -85
  311. package/dist/frontend/npm.js.map +1 -1
  312. package/dist/frontend/program.d.ts +3 -1
  313. package/dist/frontend/program.js +9 -4
  314. package/dist/frontend/program.js.map +1 -1
  315. package/dist/frontend/provenance-registry.d.ts +0 -2
  316. package/dist/frontend/provenance-registry.js +0 -10
  317. package/dist/frontend/provenance-registry.js.map +1 -1
  318. package/dist/frontend/provenance.js +4 -7
  319. package/dist/frontend/provenance.js.map +1 -1
  320. package/dist/frontend/resolve.d.ts +7 -2
  321. package/dist/frontend/resolve.js +12 -17
  322. package/dist/frontend/resolve.js.map +1 -1
  323. package/dist/frontend/resolve.test.d.ts +1 -0
  324. package/dist/frontend/resolve.test.js +29 -0
  325. package/dist/frontend/resolve.test.js.map +1 -0
  326. package/dist/frontend/ts7/adapter.d.ts +2 -2
  327. package/dist/frontend/ts7/adapter.js +1 -1
  328. package/dist/frontend/ts7/adapter.js.map +1 -1
  329. package/dist/frontend/ts7/checker.js +2 -36
  330. package/dist/frontend/ts7/checker.js.map +1 -1
  331. package/dist/frontend/ts7/enums.js +2 -1
  332. package/dist/frontend/ts7/enums.js.map +1 -1
  333. package/dist/frontend/ts7/{program.js → program-adapter.js} +7 -6
  334. package/dist/frontend/ts7/program-adapter.js.map +1 -0
  335. package/dist/frontend/ts7/world-check.d.ts +1 -3
  336. package/dist/frontend/ts7/world-check.js +3 -1
  337. package/dist/frontend/ts7/world-check.js.map +1 -1
  338. package/dist/frontend/tsc-codes.d.ts +8 -0
  339. package/dist/frontend/tsc-codes.js +109 -0
  340. package/dist/frontend/tsc-codes.js.map +1 -0
  341. package/dist/frontend/{types.d.ts → type-mapper.d.ts} +2 -25
  342. package/dist/frontend/{types.js → type-mapper.js} +12 -11
  343. package/dist/frontend/type-mapper.js.map +1 -0
  344. package/dist/frontend/workspace-registry.d.ts +26 -0
  345. package/dist/frontend/workspace-registry.js +71 -0
  346. package/dist/frontend/workspace-registry.js.map +1 -0
  347. package/dist/index.d.ts +113 -31
  348. package/dist/index.js +536 -128
  349. package/dist/index.js.map +1 -1
  350. package/dist/ir/analysis.d.ts +37 -0
  351. package/dist/ir/analysis.js +118 -0
  352. package/dist/ir/analysis.js.map +1 -0
  353. package/dist/ir/analysis.test.d.ts +1 -0
  354. package/dist/ir/analysis.test.js +21 -0
  355. package/dist/ir/analysis.test.js.map +1 -0
  356. package/dist/ir/build.d.ts +9 -0
  357. package/dist/ir/build.js +33 -0
  358. package/dist/ir/build.js.map +1 -0
  359. package/dist/ir/integer-loops.d.ts +1 -1
  360. package/dist/ir/{nodes.d.ts → ir.d.ts} +119 -37
  361. package/dist/ir/{nodes.js → ir.js} +170 -166
  362. package/dist/ir/ir.js.map +1 -0
  363. package/dist/ir/ir.test.d.ts +1 -0
  364. package/dist/ir/ir.test.js +17 -0
  365. package/dist/ir/ir.test.js.map +1 -0
  366. package/dist/ir/serialize.d.ts +2 -2
  367. package/dist/ir/serialize.js +3 -2
  368. package/dist/ir/serialize.js.map +1 -1
  369. package/dist/ir/validate.d.ts +1 -1
  370. package/dist/ir/validate.js +93 -41
  371. package/dist/ir/validate.js.map +1 -1
  372. package/dist/library/cache-primitives.d.ts +24 -0
  373. package/dist/library/cache-primitives.js +83 -0
  374. package/dist/library/cache-primitives.js.map +1 -0
  375. package/dist/library/cache-reset.test.d.ts +1 -0
  376. package/dist/library/cache-reset.test.js +47 -0
  377. package/dist/library/cache-reset.test.js.map +1 -0
  378. package/dist/library/{implementation-identity.js → compiler-self-identity.js} +1 -1
  379. package/dist/library/compiler-self-identity.js.map +1 -0
  380. package/dist/library/fence-eval.d.ts +3 -1
  381. package/dist/library/fence-eval.js +8 -2
  382. package/dist/library/fence-eval.js.map +1 -1
  383. package/dist/library/int-infer.d.ts +1 -36
  384. package/dist/library/int-infer.js +29 -18
  385. package/dist/library/int-infer.js.map +1 -1
  386. package/dist/library/int-infer.test.js +4 -4
  387. package/dist/library/{early-cache.d.ts → library-cache.d.ts} +1 -1
  388. package/dist/library/{early-cache.js → library-cache.js} +34 -89
  389. package/dist/library/library-cache.js.map +1 -0
  390. package/dist/library/library-cache.test.d.ts +1 -0
  391. package/dist/library/{early-cache.test.js → library-cache.test.js} +7 -7
  392. package/dist/library/library-cache.test.js.map +1 -0
  393. package/dist/library/{profile.d.ts → library-profile.d.ts} +4 -7
  394. package/dist/library/{profile.js → library-profile.js} +18 -11
  395. package/dist/library/library-profile.js.map +1 -0
  396. package/dist/library/semantic-source.js +2 -1
  397. package/dist/library/semantic-source.js.map +1 -1
  398. package/dist/library/sidecar.d.ts +5 -2
  399. package/dist/library/sidecar.js +11 -5
  400. package/dist/library/sidecar.js.map +1 -1
  401. package/dist/startup-cache.d.ts +11 -3
  402. package/dist/startup-cache.js +17 -2
  403. package/dist/startup-cache.js.map +1 -1
  404. package/package.json +19 -2
  405. package/surface-manifest.json +5 -5
  406. package/dist/backend/cc-cache.test.js.map +0 -1
  407. package/dist/backend/cc.js.map +0 -1
  408. package/dist/backend/emission/emit-async.js.map +0 -1
  409. package/dist/backend/emission/emit-exprs.d.ts +0 -13
  410. package/dist/backend/emission/emit-exprs.js +0 -7407
  411. package/dist/backend/emission/emit-exprs.js.map +0 -1
  412. package/dist/backend/emission/emit-island.js.map +0 -1
  413. package/dist/backend/emission/emit-shapes.js.map +0 -1
  414. package/dist/backend/emission/emit-stmts.js.map +0 -1
  415. package/dist/backend/emission/emit-types.js.map +0 -1
  416. package/dist/backend/emission/emit-walkers.js.map +0 -1
  417. package/dist/backend/emission/emitter.js.map +0 -1
  418. package/dist/backend/emission/may-throw.js.map +0 -1
  419. package/dist/backend/library-identity.js.map +0 -1
  420. package/dist/executable/early-cache.js.map +0 -1
  421. package/dist/executable/early-cache.test.js.map +0 -1
  422. package/dist/ffi/profile.js.map +0 -1
  423. package/dist/frontend/lowering/lower-emitter.js.map +0 -1
  424. package/dist/frontend/shared.d.ts +0 -82
  425. package/dist/frontend/shared.js +0 -308
  426. package/dist/frontend/shared.js.map +0 -1
  427. package/dist/frontend/ts7/program.js.map +0 -1
  428. package/dist/frontend/types.js.map +0 -1
  429. package/dist/ir/nodes.js.map +0 -1
  430. package/dist/library/early-cache.js.map +0 -1
  431. package/dist/library/early-cache.test.js.map +0 -1
  432. package/dist/library/implementation-identity.js.map +0 -1
  433. package/dist/library/profile.js.map +0 -1
  434. /package/dist/backend/{cc-cache.test.d.ts → c/types.test.d.ts} +0 -0
  435. /package/dist/{executable/early-cache.test.d.ts → backend/llvm/shapes.test.d.ts} +0 -0
  436. /package/dist/{library/early-cache.test.d.ts → backend/native-codegen.test.d.ts} +0 -0
  437. /package/dist/ffi/{profile.d.ts → ffi-manifest.d.ts} +0 -0
  438. /package/dist/frontend/ts7/{program.d.ts → program-adapter.d.ts} +0 -0
  439. /package/dist/library/{implementation-identity.d.ts → compiler-self-identity.d.ts} +0 -0
@@ -1,3 +1,4 @@
1
+ import { InternalCompilerError } from "../../errors.js";
1
2
  /* AST + checker → IR.
2
3
  *
3
4
  * Invariants:
@@ -13,13 +14,14 @@
13
14
  * ("x.0", "x.1" for shadowing); the IR is scope-flat.
14
15
  */
15
16
  import { resolve } from "node:path";
16
- import { isRelativeSpecifier, tsgoPath } from "../shared.js";
17
+ import { tsgoPath } from "../dts-paths.js";
18
+ import { isRelativeSpecifier } from "../workspace-registry.js";
17
19
  import * as ts from "../ts7/adapter.js";
18
20
  import { anyOpRequiresDynamicDiag, blockedBindingUseDiag, checkerPanicDiag, componentTypeDiag, isCheckerPanic, genericSignatureTypeDiag, indexSignatureTypeDiag, intersectionTypeDiag, noLoweringDiag, overloadedSignatureTypeDiag, recordShapeMismatchDiag, requiresDynamicApiDiag, requiresDynamicPackageDiag, requiresDynamicTypeDiag, unionMismatchDiag, unsupportedDiag, unsupportedTypeDiag, } from "../../diagnostics/diagnostic.js";
19
- import { arrayOf, BOOL, canAdaptDynFuncTo, canConvertToDyn, canCrossIslandBoundary, canExitIslandToType, canMarshalTypedFuncIntoIsland, DYN, F64, isJsonSafeType, isUndefinedArmedUnion, isUnitType, JSVAL, RUNTIME_ERROR_CLASSES, STRING, typeEquals, UNDEFINED_T, VOID } from "../../ir/nodes.js";
21
+ import { arrayOf, BOOL, canAdaptDynFuncTo, canConvertToDyn, canCrossIslandBoundary, canExitIslandToType, canMarshalTypedFuncIntoIsland, DYN, F64, isJsonSafeType, isJsonStringifySafeType, isUndefinedArmedUnion, isUnitType, JSVAL, RUNTIME_ERROR_CLASSES, STRING, typeEquals, UNDEFINED_T, VOID } from "../../ir/ir.js";
20
22
  import { provenanceActive } from "../provenance-registry.js";
21
23
  import { ambientDtsPath, canonicalBuiltinModule, cjsExportAssignmentOf, cjsExportDiscardReason, fallbackDtsPath, isCjsExportTableLiteral, isJsSourceFile, isNodeEsmFile, isNodeTypesPath, locOf, orderedImportsOf, overridesDtsPath, npmStaticDepSf7, requireSpecOf, resolveImport, workspacePackageOfPath, } from "../program.js";
22
- import { containsRecord, containsUnion, describeComponentBlocker, describeRecordMemberBlocker, formatIrType, ISLAND_AMBIENT_TYPES, isUnitOnlyTsType, mapType, ShapeRegistry, typeKey, UnionRegistry, withUndefinedArm as withUndefinedArmCanonical, } from "../types.js";
24
+ import { containsRecord, containsUnion, describeComponentBlocker, describeRecordMemberBlocker, formatIrType, ISLAND_AMBIENT_TYPES, isUnitOnlyTsType, mapType, ShapeRegistry, typeKey, UnionRegistry, withUndefinedArm as withUndefinedArmCanonical, } from "../type-mapper.js";
23
25
  import { boundaryIntoIslandMsg, boundaryOutOfIslandMsg, builtinConstLit, builtinModuleConstOf, builtinModulesArrayLit, builtinFenceHintOf, builtinModuleFnOf, stdlibMemberFence, isStdlibMember, isStdlibSymbol, isStdlibGlobal, stdlibGlobalMember, nodeTypesOnlySymbol } from "./surfaces.js";
24
26
  import { splitFiles, collectProgram, collectNpmImports, collectJsonImports, moduleArtifacts, collectGlobals, declSymbolOf, defaultExportSymbolOf, lowerFileInit, lowerDefaultExport, buildMain, appendDynamicImportModules } from "./lower-modules.js";
25
27
  import { registerBuiltinErrorClasses, registerBuiltinEmitterClass, registerBuiltinStreamClasses, builtinErrorInfoOf, builtinEmitterInfoOf, builtinStreamInfoOf, analyzeClassDecoration, classIteratorDrainCall, classIteratorNextCall, classIteratorOf, classIteratorOpenCall, classIteratorRestDrainCall, classMemberNameOf, classValueRef, collectClassShape, exactClassOfReceiver, collectClassShapeInner, ctorAbiEquals, findMethodOn, findStaticOn, findGenericMethodOn, findGenericStaticOn, genericClassInstanceType, isSubclassOf, inHierarchy, overrideBelow, staticShadowBelow, upcastTo, lowerClassMembers, lowerClassCtor, lowerClassExpression, lowerClassExpressionInfo, lowerClassMethodMember, lowerClassValueProperty, lowerStaticMethod, throwingSetterFn, fieldInitStmts, lowerStaticFieldInits, lowerStaticFieldRead, lowerDerivedCtorBody, superCallStmt, lowerSuperMethodCall, superThisRef, lowerSuperAccessorRead, lowerSuperAccessorWrite, inheritsBuiltinErrorCtor, inheritsBuiltinEmitterCtor, errorMessageArg, lowerNew, accessorCall } from "./lower-classes.js";
@@ -27,7 +29,7 @@ import { mixinCallClassInfoOf, mixinIntersectionInstanceType } from "./lower-mix
27
29
  import { bindingNeverReassigned, bodyReadsArguments, implicitMonoFile, isThisParameter, paramShape, paramShapes, checkDefaultParamBodyType, completeArgs, wrappedUndefined, undefinedArgFor, requireExactArityValue, bodyReturnType, declaredReturnType, collectSignature, collectSignatureInner, collectGenericSignature, genericFnOf, lowerGenericCall, lowerGenericFnValue, inferTypeParamBindings, lowerGenericInstance, lowerCall, lowerFfiCall, lowerTimersMemberCall, lowerPromiseMethodCall, lowerFilterNarrowCall, isTopLevelFnSymbol, lowerNestedFunctionDecl, lambdaSignature, lowerLambda, lowerFunction, validateFfiImports } from "./lower-calls.js";
28
30
  import { lowerArrayMethodCall, lowerBufferStaticCall, lowerBytesMethodCall, lowerBytesNew, lowerMapMethodCall, lowerMapForEachCall, buildMapForEachFn, lowerRecordOvfCaptureHelper, lowerEnvToPairsHelper, lowerSetMethodCall, lowerSetForEachCall, buildSetForEachFn, lowerRegexMethodCall, lowerStringMethodCall } from "./lower-containers.js";
29
31
  import { lowerStreamModuleCall } from "./lower-stream.js";
30
- import { lowerEmitOverrideSpec } from "./lower-emitter.js";
32
+ import { lowerEmitOverrideSpec } from "./lower-event-emitter.js";
31
33
  import { builtinImportOf, createRequireBindingDecl, createRequireNamespaceDecl, createRequireSpecOf, stripTypeCasts, lowerBuiltinModuleCall, lowerFsToUnixTimestampCall, lowerFsLadderCall, lowerChildArgsArg, lowerSpawnSyncCall, lowerSpawnCall, lowerExecSyncCall, recordToEnvPairs, lowerJsonMethodCall, fencedBuiltinImportOf, lowerCryptoComposedCall, lowerUrlMethodCall, lowerSearchParamsMethodCall, lowerStatsMethodCall, lowerChildMethodCall, lowerAtomicsCall, lowerBuiltinExtraProperty, promisifiedExecFileDecl, lowerExecFileAsyncCall, execFileAsyncHelper, lowerStringDecoderMethodCall, strdecHelper, lowerReadlineMethodCall, lowerDcChannelMethodCall, lowerDcChannelProperty, lowerAlsMethodCall, lowerDcTracingChannelMethodCall, lowerDcTracingChannelProperty, lowerJsonProperty, lowerErrorCodeProperty, lowerProcessProperty, isProcessEnv, envValueType, lowerProcessEnvGet, lowerProcessMethodCall, lowerProcessOptionalMethodCall, lowerTimeoutMethodCall, envSnapshotHelper, isConsoleLog, consoleCallMember, lowerNumberStaticCall, lowerNumberStaticProperty, lowerDateCall, lowerTextCodecCall, lowerCryptoModuleCall, lowerFsConstantsProperty, lowerBuiltinConstantsProperty, builtinConstantBindingOf, builtinConstantsDestructureDecl, lowerProcessStreamProperty, lowerStringStaticCall, lowerStringLastIndexOfCall, lowerPromiseStaticCall, textCodecBindingClassOf } from "./lower-builtins.js";
32
34
  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";
33
35
  import { lowerHttpHeadersElement, lowerNetModuleCall, lowerServerMethodCall, lowerServerProperty, lowerTlsRootCertificates } from "./lower-server.js";
@@ -40,6 +42,7 @@ import { lowerStmts, noteBlockedBindings, isBlockedBinding, lowerScopedBlock, pr
40
42
  import { lowerDynObjectLiteral, lowerExpr, maybeNarrow, lowerUnitComparison, lowerNullishCoalesce, lowerOptionalChain, finishOptionalChain, lowerCondition, ensureBool, requireTruthyUnion, eqComparableUnion, lowerIntrinsicProperty, lowerArrayLiteral, lowerObjectLiteral, lowerShorthandValue, rejectThisInObjectMethod, lowerElementAccess, lowerElementWrite, lowerRecordKeyRead, ensureString, lowerTemplate, lowerAsExpression, lowerPrefixUnary, lowerBinary, lowerCaughtTypeofTest, caughtRead, caughtLocalOf, caughtToString, lowerInstanceOf, lowerRegexLiteral, lowerFieldRead, lowerUnionProperty, fieldTarget, fieldGetExpr, fieldSetStmt, lowerFieldCompound, uniqueSymbolKeyOf, foldedStringKeyOf } from "./lower-exprs.js";
41
43
  import { lowerRecordFieldCall, lowerObjectMethodCall } from "./lower-calls.js";
42
44
  import { fenceCrossBlockNsRef, nsPathPrefix } from "./lower-namespaces.js";
45
+ import { numLit, varRef } from "../../ir/build.js";
43
46
  /** Entry function name. '%' cannot appear in a TS identifier, so a user
44
47
  * function can never collide with it (mangling is injective per prefix). */
45
48
  export const ENTRY_NAME = "%main";
@@ -56,7 +59,7 @@ export function own(table, key) {
56
59
  /** Sentinel binding key for `this` (which has no ts.Symbol): a stable
57
60
  * object identity used in the same scope/capture maps as real symbols, so
58
61
  * arrows capturing `this` ride the ordinary capture machinery. */
59
- export const THIS_BINDING = { escapedName: "%this" };
62
+ const THIS_BINDING = { escapedName: "%this" };
60
63
  export function newFnCtx(lifted, selfSymbol, selfType, returnType) {
61
64
  return {
62
65
  locals: [],
@@ -76,9 +79,9 @@ export function newFnCtx(lifted, selfSymbol, selfType, returnType) {
76
79
  * visit; descending would attribute a nested island statement to every
77
80
  * enclosing construct too). The top-level statement object itself is
78
81
  * always visited. */
79
- export const IR_STMT_KINDS = new Set([
82
+ const IR_STMT_KINDS = new Set([
80
83
  "varDecl", "assign", "exprStmt", "if", "while", "doWhile", "switch",
81
- "arraySet", "forOf", "return", "fieldSet", "recordSet", "break",
84
+ "arraySet", "arraySetLength", "arraySetUndefined", "arrayDelete", "forOf", "return", "fieldSet", "recordSet", "break",
82
85
  "continue", "block", "tryCatch", "throw", "rethrow", "runtimeFence",
83
86
  ]);
84
87
  /** True when a lowered statement's OWN expressions contain island
@@ -308,8 +311,8 @@ export function importCallHandleType(expr) {
308
311
  * Ambient (.d.ts) declarations never reach this: they have no compiled
309
312
  * implementation, so their calls lower through the island/builtin paths
310
313
  * whose validated exits keep the checker-trust trap. */
311
- export function uncheckedOverloadHandleCall(L, expr) {
312
- if (!L.dynamic || !expr)
314
+ export function uncheckedOverloadHandleCall(lowerer, expr) {
315
+ if (!lowerer.dynamic || !expr)
313
316
  return false;
314
317
  let e = expr;
315
318
  while (ts.isParenthesizedExpression(e))
@@ -319,25 +322,25 @@ export function uncheckedOverloadHandleCall(L, expr) {
319
322
  // overload of an any-returning implementation stores the handle.
320
323
  if (!ts.isCallExpression(e) && !ts.isTaggedTemplateExpression(e))
321
324
  return false;
322
- const rsig = L.checker.getResolvedSignature(e);
323
- const rdecl = rsig ? L.checker.signatureDeclaration(rsig) : undefined;
325
+ const rsig = lowerer.checker.getResolvedSignature(e);
326
+ const rdecl = rsig ? lowerer.checker.signatureDeclaration(rsig) : undefined;
324
327
  if (!rsig || !rdecl)
325
328
  return false;
326
329
  if (!(ts.isFunctionDeclaration(rdecl) || ts.isMethodDeclaration(rdecl)) || rdecl.body)
327
330
  return false;
328
331
  const name = rdecl.name;
329
- const symbol = name ? L.checker.getSymbolAtLocation(name) : undefined;
332
+ const symbol = name ? lowerer.checker.getSymbolAtLocation(name) : undefined;
330
333
  if (!symbol)
331
334
  return false;
332
- const impl = L.checker
335
+ const impl = lowerer.checker
333
336
  .declarationsOf(symbol)
334
337
  .find((d) => (ts.isFunctionDeclaration(d) || ts.isMethodDeclaration(d)) && d.body !== undefined);
335
338
  if (!impl)
336
339
  return false;
337
- const implSig = L.checker.getSignatureFromDeclaration(impl);
340
+ const implSig = lowerer.checker.getSignatureFromDeclaration(impl);
338
341
  if (!implSig)
339
342
  return false;
340
- return L.mapTypeOf(L.checker.getReturnTypeOfSignature(implSig))?.kind === "jsval";
343
+ return lowerer.mapTypeOf(lowerer.checker.getReturnTypeOfSignature(implSig))?.kind === "jsval";
341
344
  }
342
345
  /** The JavaScript declaration fallback for unmappable binding types (see
343
346
  * irTypeOf): `any` and every other inference residue is the checked-
@@ -356,7 +359,7 @@ export function uncheckedOverloadHandleCall(L, expr) {
356
359
  * checked-dynamic fallbacks apply, the pre-never-mapping behavior. Bare
357
360
  * `never` at the ROOT stays out (`for (const v of [])`'s loop var — the
358
361
  * dead read the f64 mapping is FOR). */
359
- export function neverTaintedJsType(L, node, t) {
362
+ export function neverTaintedJsType(lowerer, node, t) {
360
363
  if (!isJsSourceFile(node.getSourceFile()))
361
364
  return false;
362
365
  const walk = (x, depth) => {
@@ -364,8 +367,8 @@ export function neverTaintedJsType(L, node, t) {
364
367
  return false;
365
368
  if (x.isUnionType())
366
369
  return ts.constituentTypes(x).some((a) => walk(a, depth - 1));
367
- if (L.checker.isArrayType(x) || L.checker.isTupleType(x)) {
368
- return L.checker
370
+ if (lowerer.checker.isArrayType(x) || lowerer.checker.isTupleType(x)) {
371
+ return lowerer.checker
369
372
  .getTypeArguments(x)
370
373
  .some((a) => (a.flags & ts.TypeFlags.Never) !== 0 || walk(a, depth - 1));
371
374
  }
@@ -414,10 +417,10 @@ export function nodeThrowExpr(kind, code, message, type, loc) {
414
417
  * (scr_throw_lowering_fence). The diagnostic joins the runtime-fence
415
418
  * ledger exactly like a deferred statement fence — nothing silently
416
419
  * drops off the coverage report. */
417
- export function ladderFenceExpr(L, surface, node, hint) {
420
+ export function ladderFenceExpr(lowerer, surface, node, hint) {
418
421
  const loc = locOf(node);
419
422
  const d = noLoweringDiag(surface, loc, hint);
420
- L.runtimeFences.push(d);
423
+ lowerer.runtimeFences.push(d);
421
424
  const sf = node.getSourceFile();
422
425
  const pos = ts.getLineAndCharacterOfPosition(sf, loc.start);
423
426
  return {
@@ -450,7 +453,7 @@ export function ladderFenceExpr(L, surface, node, hint) {
450
453
  * this fallback for `any` (mapType answers jsval first).
451
454
  *
452
455
  * Null for void (no value exists to represent). */
453
- export function dynFallbackType(L, node, t) {
456
+ export function dynFallbackType(lowerer, node, t) {
454
457
  if (t.flags & ts.TypeFlags.Void)
455
458
  return null;
456
459
  if (!isJsSourceFile(node.getSourceFile())) {
@@ -459,13 +462,13 @@ export function dynFallbackType(L, node, t) {
459
462
  // TS single-call-signature function types: per-piece fallback, but
460
463
  // ONLY `any` pieces fall to dyn — any other unmappable piece keeps
461
464
  // the whole type's own fence.
462
- return anyPiecedFuncType(L, node, t);
465
+ return anyPiecedFuncType(lowerer, node, t);
463
466
  }
464
- if (L.checker.isArrayType(t)) {
465
- const elem = L.checker.getTypeArguments(t)[0];
467
+ if (lowerer.checker.isArrayType(t)) {
468
+ const elem = lowerer.checker.getTypeArguments(t)[0];
466
469
  const elemTainted = elem !== undefined &&
467
- ((elem.flags & ts.TypeFlags.Never) !== 0 || neverTaintedJsType(L, node, elem));
468
- const mappedElem = elem !== undefined && !elemTainted ? L.mapTypeOf(elem) : null;
470
+ ((elem.flags & ts.TypeFlags.Never) !== 0 || neverTaintedJsType(lowerer, node, elem));
471
+ const mappedElem = elem !== undefined && !elemTainted ? lowerer.mapTypeOf(elem) : null;
469
472
  // A mappable element keeps the static array; an unmappable one makes
470
473
  // the WHOLE value dyn (the checked-dynamic tree has real arrays — length/index/push
471
474
  // read through the keyed-dyn paths; dyn-element STATIC arrays have no
@@ -482,14 +485,14 @@ export function dynFallbackType(L, node, t) {
482
485
  // construct signatures, overloads, and function-with-properties shapes
483
486
  // stay out (the whole value falls to dyn below, where every reached
484
487
  // use meets its own fence or boxes as-is).
485
- const sig = pureSingleCallSignatureOf(L, t);
488
+ const sig = pureSingleCallSignatureOf(lowerer, t);
486
489
  if (sig) {
487
490
  const params = sig.getParameters().map((p) => {
488
- const pt = L.checker.getTypeOfSymbolAtLocation(p, node);
489
- return L.mapTypeOf(pt) ?? DYN;
491
+ const pt = lowerer.checker.getTypeOfSymbolAtLocation(p, node);
492
+ return lowerer.mapTypeOf(pt) ?? DYN;
490
493
  });
491
- const retT = L.checker.getReturnTypeOfSignature(sig);
492
- const ret = retT.flags & ts.TypeFlags.Void ? VOID : L.mapTypeOf(retT) ?? DYN;
494
+ const retT = lowerer.checker.getReturnTypeOfSignature(sig);
495
+ const ret = retT.flags & ts.TypeFlags.Void ? VOID : lowerer.mapTypeOf(retT) ?? DYN;
493
496
  return { kind: "func", params, ret };
494
497
  }
495
498
  return DYN;
@@ -498,23 +501,23 @@ export function dynFallbackType(L, node, t) {
498
501
  * properties, no construct signatures, no type parameters, no rest params
499
502
  * (declared or synthesized from an `arguments` read). Null for every
500
503
  * other shape. The structural gate both dynFallbackType arms share. */
501
- function pureSingleCallSignatureOf(L, t) {
504
+ function pureSingleCallSignatureOf(lowerer, t) {
502
505
  if (!(t.flags & ts.TypeFlags.Object))
503
506
  return null;
504
- const sigs = L.checker.getCallSignatures(t);
507
+ const sigs = lowerer.checker.getCallSignatures(t);
505
508
  if (sigs.length === 1 &&
506
- L.checker.getPropertiesOfType(t).length === 0 &&
507
- L.checker.getConstructSignatures(t).length === 0 &&
509
+ lowerer.checker.getPropertiesOfType(t).length === 0 &&
510
+ lowerer.checker.getConstructSignatures(t).length === 0 &&
508
511
  sigs[0].getTypeParameters().length === 0 &&
509
512
  sigs[0].getParameters().every((p) => {
510
- const pDecl = L.checker.valueDeclarationOf(p);
513
+ const pDecl = lowerer.checker.valueDeclarationOf(p);
511
514
  return !pDecl || !ts.isParameter(pDecl) || pDecl.dotDotDotToken === undefined;
512
515
  }) &&
513
516
  // A SYNTHESIZED rest param (tsc's `arguments` inference — no
514
517
  // valueDeclaration to carry the dotDotDot): param-count mismatch
515
518
  // against the signature's declaration; the whole value stays dyn.
516
519
  (() => {
517
- const sigDecl = L.checker.signatureDeclaration(sigs[0]);
520
+ const sigDecl = lowerer.checker.signatureDeclaration(sigs[0]);
518
521
  const declParams = sigDecl !== undefined && ts.isFunctionLike(sigDecl) ? sigDecl.parameters : undefined;
519
522
  if (declParams !== undefined && declParams.length !== sigs[0].getParameters().length)
520
523
  return false;
@@ -534,21 +537,21 @@ function pureSingleCallSignatureOf(L, t) {
534
537
  * irTypeOf fallback, so the binding type and the closure type agree).
535
538
  * A piece that fails to map for any other reason answers null — the
536
539
  * whole type keeps its own diagnostic. */
537
- function anyPiecedFuncType(L, node, t) {
538
- const sig = pureSingleCallSignatureOf(L, t);
540
+ function anyPiecedFuncType(lowerer, node, t) {
541
+ const sig = pureSingleCallSignatureOf(lowerer, t);
539
542
  if (!sig)
540
543
  return null;
541
544
  const params = [];
542
545
  for (const p of sig.getParameters()) {
543
- const pt = L.checker.getTypeOfSymbolAtLocation(p, node);
544
- const mapped = L.mapTypeOf(pt) ?? (pt.flags & ts.TypeFlags.Any ? DYN : null);
546
+ const pt = lowerer.checker.getTypeOfSymbolAtLocation(p, node);
547
+ const mapped = lowerer.mapTypeOf(pt) ?? (pt.flags & ts.TypeFlags.Any ? DYN : null);
545
548
  if (!mapped || mapped.kind === "void")
546
549
  return null;
547
550
  params.push(mapped);
548
551
  }
549
- const retT = L.checker.getReturnTypeOfSignature(sig);
552
+ const retT = lowerer.checker.getReturnTypeOfSignature(sig);
550
553
  const ret = retT.flags & (ts.TypeFlags.Void | ts.TypeFlags.Never) ? VOID
551
- : L.mapTypeOf(retT) ?? (retT.flags & ts.TypeFlags.Any ? DYN : null);
554
+ : lowerer.mapTypeOf(retT) ?? (retT.flags & ts.TypeFlags.Any ? DYN : null);
552
555
  if (!ret)
553
556
  return null;
554
557
  return { kind: "func", params, ret };
@@ -818,12 +821,233 @@ export class Lowerer {
818
821
  /** All storage slots widened for runtime absence, including slots whose
819
822
  * current control-flow branch has temporarily narrowed the value. */
820
823
  runtimeOptionalStorageLocals = new Set();
824
+ /** Globals whose checker-bare type was widened because an indexed read can
825
+ * carry undefined at runtime. Identifier reads keep the union tag so
826
+ * typeof and later boundaries observe the real value. */
827
+ runtimeOptionalGlobals = new Set();
828
+ /** Bindings whose unchecked string arithmetic can produce either a number
829
+ * (NaN for an absent read) or a string. Preserve that result union at bare
830
+ * reads instead of applying the checker-bare string narrowing adapter. */
831
+ runtimeOptionalArithmeticLocals = new Set();
832
+ runtimeOptionalArithmeticGlobals = new Set();
833
+ /** Binding symbols whose IR storage type was widened by the indexed-read
834
+ * prepass. This includes explicit annotations: unchecked TS annotations do
835
+ * not prove that an array property read produced a value. */
836
+ runtimeOptionalBindingTypes = new Map();
837
+ /** Concise callback/lambda returns promoted by the HOF callback prepass;
838
+ * arrows have no declaration symbol to key in fnSigsBySymbol. */
839
+ runtimeOptionalFunctionReturns = new WeakMap();
840
+ /** Arithmetic over an unchecked string read can answer either NaN or a
841
+ * string. Bindings and returns use this marker to retain that result union
842
+ * through checker-bare string annotations. */
843
+ runtimeOptionalArithmeticTypes = new WeakMap();
844
+ /** Record fields promoted to an undefined-armed union by an indexed-read
845
+ * value. The key is the concrete emitted shape and field name. */
846
+ runtimeOptionalFields = new Set();
847
+ /** Callback pattern parameters carry an optional source without making
848
+ * every name destructured from a present source optional. */
849
+ runtimeOptionalPatternTypes = new WeakMap();
850
+ runtimeOptionalReduceTypes = new WeakMap();
821
851
  /** Capture entries and their origin share one mutable box. Normalize each
822
852
  * entry to the origin so writes and flow proofs stay synchronized. */
823
853
  runtimeOptionalRoots = new Map();
824
854
  runtimeOptionalRootOf(local) {
825
855
  return this.runtimeOptionalRoots.get(local) ?? local;
826
856
  }
857
+ runtimeOptionalBindingType(node, fallback) {
858
+ const patternType = this.runtimeOptionalPatternTypes.get(node);
859
+ if (patternType)
860
+ return patternType;
861
+ const symbol = ts.isIdentifier(node) ? this.resolveValueSymbol(node) : this.checker.getSymbolAtLocation(node);
862
+ if (!symbol)
863
+ return fallback ?? null;
864
+ const known = this.runtimeOptionalBindingTypes.get(symbol);
865
+ if (known)
866
+ return known;
867
+ // A module-scope function alias is collected as a global before the
868
+ // optional-read fixed point settles. Derive its promoted function ABI
869
+ // directly from the aliased declaration as a final read-side hook, so
870
+ // the initializer cannot fall back to a narrowing adapter.
871
+ if (ts.isIdentifier(node) && fallback?.kind === "func") {
872
+ const decl = this.checker.valueDeclarationOf(symbol);
873
+ if (decl && ts.isVariableDeclaration(decl) && decl.initializer) {
874
+ let init = decl.initializer;
875
+ while (ts.isParenthesizedExpression(init))
876
+ init = init.expression;
877
+ if (ts.isIdentifier(init)) {
878
+ const source = this.resolveValueSymbol(init);
879
+ const sig = source ? this.fnSigsBySymbol.get(source) : undefined;
880
+ if (sig) {
881
+ return {
882
+ ...fallback,
883
+ params: sig.params.filter((p) => p.mode !== "dynRest").map((p) => p.type),
884
+ ret: sig.returnType,
885
+ };
886
+ }
887
+ }
888
+ }
889
+ }
890
+ return fallback ?? null;
891
+ }
892
+ runtimeOptionalIdentifierValue(node) {
893
+ if (!ts.isIdentifier(node) || this.chainRecvByNode.has(node))
894
+ return null;
895
+ const local = this.resolveLocal(node);
896
+ const symbol = this.resolveValueSymbol(node);
897
+ const storage = local ?? (symbol ? this.globalsBySymbol.get(symbol) : undefined);
898
+ if (!storage || storage.type.kind !== "union" || this.armTag(storage.type.unionId, UNDEFINED_T) < 0)
899
+ return null;
900
+ const present = this.stripUndefinedArm(storage.type);
901
+ if (isUnitType(present))
902
+ return null;
903
+ return { value: varRef(storage.id, storage.type, locOf(node)), present, unionId: storage.type.unionId };
904
+ }
905
+ /** Recover the original optional union when a checked single-arm helper
906
+ * was installed before a strict property consumer could name its member.
907
+ * Recovery is limited to array element reads and storage roots marked by
908
+ * the optional-read analysis, so ordinary assertions keep their generic
909
+ * checked-narrow behavior. */
910
+ runtimeOptionalSourceValue(node, value) {
911
+ let origin = node;
912
+ while (ts.isParenthesizedExpression(origin))
913
+ origin = origin.expression;
914
+ let optionalOrigin = ts.isElementAccessExpression(origin);
915
+ if (ts.isIdentifier(origin)) {
916
+ const local = this.resolveLocal(origin);
917
+ const root = local ? this.runtimeOptionalRootOf(local) : null;
918
+ const global = this.globalOf(origin);
919
+ optionalOrigin =
920
+ (!!root && this.runtimeOptionalStorageLocals.has(root)) ||
921
+ (!!global && (this.isRuntimeOptionalGlobal(global) ||
922
+ (global.type.kind === "union" && this.armTag(global.type.unionId, UNDEFINED_T) >= 0)));
923
+ }
924
+ if (!optionalOrigin)
925
+ return null;
926
+ let source = value;
927
+ if (value.kind === "call" &&
928
+ this.checkedNarrowHelpers.has(value.callee) &&
929
+ value.args.length === 1 &&
930
+ value.args[0]?.type.kind === "union") {
931
+ source = value.args[0];
932
+ }
933
+ return source.type.kind === "union" && this.armTag(source.type.unionId, UNDEFINED_T) >= 0
934
+ ? source
935
+ : null;
936
+ }
937
+ /** A strict property or method receiver over an array-derived optional
938
+ * value. Stabilize the receiver once, throw Node's member-read TypeError
939
+ * for a unit arm, and extract the expected present arm otherwise. */
940
+ runtimeOptionalPropertyReceiver(node, value, expected, member) {
941
+ const source = this.runtimeOptionalSourceValue(node, value);
942
+ if (source?.type.kind !== "union")
943
+ return null;
944
+ const def = this.unions.get(source.type.unionId);
945
+ const valueTag = this.armTag(source.type.unionId, expected);
946
+ if (!def ||
947
+ valueTag < 0 ||
948
+ !def.arms.every((arm) => typeEquals(arm, expected) || isUnitType(arm)))
949
+ return null;
950
+ const loc = locOf(node);
951
+ const stable = this.declareHiddenLocal("%propertyRecv", source.type);
952
+ const stableRef = () => varRef(stable.id, source.type, loc);
953
+ let result = {
954
+ kind: "unionNarrow",
955
+ unionId: source.type.unionId,
956
+ tag: valueTag,
957
+ value: stableRef(),
958
+ type: expected,
959
+ loc,
960
+ };
961
+ for (let i = def.arms.length - 1; i >= 0; i--) {
962
+ const arm = def.arms[i];
963
+ if (!arm || !isUnitType(arm))
964
+ continue;
965
+ const unit = arm.kind === "nullT" ? "null" : "undefined";
966
+ result = {
967
+ kind: "ternary",
968
+ cond: {
969
+ kind: "unionIsTag",
970
+ unionId: source.type.unionId,
971
+ tag: i,
972
+ negated: false,
973
+ value: stableRef(),
974
+ type: BOOL,
975
+ loc,
976
+ },
977
+ then: nodeThrowExpr(1, "", `Cannot read properties of ${unit} (reading '${member}')`, expected, loc),
978
+ else_: result,
979
+ type: expected,
980
+ loc,
981
+ };
982
+ }
983
+ return {
984
+ kind: "seqExpr",
985
+ stmts: [{ kind: "varDecl", localId: stable.id, init: source, loc }],
986
+ result,
987
+ type: expected,
988
+ loc,
989
+ };
990
+ }
991
+ runtimeOptionalFieldKey(shapeId, field) {
992
+ return `${shapeId}:${field}`;
993
+ }
994
+ isRuntimeOptionalField(shapeId, field) {
995
+ return this.runtimeOptionalFields.has(this.runtimeOptionalFieldKey(shapeId, field));
996
+ }
997
+ isRuntimeOptionalGlobal(global) {
998
+ return this.runtimeOptionalGlobals.has(global);
999
+ }
1000
+ isRuntimeOptionalArithmeticGlobal(global) {
1001
+ return this.runtimeOptionalArithmeticGlobals.has(global);
1002
+ }
1003
+ /** The union produced when an unchecked array read reaches a typed slot
1004
+ * whose checker type is the corresponding bare arm. */
1005
+ runtimeOptionalWidening(actual, expected) {
1006
+ if (actual.kind !== "union" || this.armTag(actual.unionId, UNDEFINED_T) < 0)
1007
+ return null;
1008
+ return typeEquals(this.stripUndefinedArm(actual), expected) ? actual : null;
1009
+ }
1010
+ runtimeOptionalType(t) {
1011
+ if (t.kind === "union")
1012
+ return this.armTag(t.unionId, UNDEFINED_T) >= 0 ? t : this.withUndefinedArmOf(t) ?? t;
1013
+ if (t.kind === "void" || t.kind === "dyn" || t.kind === "jsval" || t.kind === "generator")
1014
+ return t;
1015
+ return this.withUndefinedArm(t);
1016
+ }
1017
+ promoteRuntimeOptionalParameter(node, type) {
1018
+ const widened = this.runtimeOptionalType(type);
1019
+ const symbol = this.checker.getSymbolAtLocation(node);
1020
+ if (symbol)
1021
+ this.runtimeOptionalBindingTypes.set(symbol, widened);
1022
+ return widened;
1023
+ }
1024
+ promoteRuntimeOptionalFunctionReturn(node, type) {
1025
+ const widened = this.runtimeOptionalType(type);
1026
+ this.runtimeOptionalFunctionReturns.set(node, widened);
1027
+ return widened;
1028
+ }
1029
+ runtimeOptionalFunctionReturnType(node, fallback) {
1030
+ return this.runtimeOptionalFunctionReturns.get(node) ?? fallback;
1031
+ }
1032
+ /** Promote one field of a record storage shape to the value's runtime
1033
+ * type. Shapes are immutable by identity, so this interns a sibling shape
1034
+ * and records the field as runtime-optional for property-read narrowing. */
1035
+ runtimeOptionalRecordField(type, field, fieldType) {
1036
+ if (type.kind !== "record")
1037
+ return type;
1038
+ const shape = this.shapes.get(type.shapeId);
1039
+ if (!shape)
1040
+ return type;
1041
+ const existing = shape.fields.find((f) => f.name === field);
1042
+ if (!existing || typeEquals(existing.type, fieldType)) {
1043
+ if (existing)
1044
+ this.runtimeOptionalFields.add(this.runtimeOptionalFieldKey(type.shapeId, field));
1045
+ return type;
1046
+ }
1047
+ const shapeId = this.shapes.intern(shape.fields.map((f) => ({ name: f.name, type: f.name === field ? fieldType : f.type })), shape.tuple === true, shape.indexValue, shape.declaredOrder);
1048
+ this.runtimeOptionalFields.add(this.runtimeOptionalFieldKey(shapeId, field));
1049
+ return { kind: "record", shapeId };
1050
+ }
827
1051
  /** Runs `fn` with the given aliased-typeof narrows applied (and restored
828
1052
  * after) — the branch-scoping primitive. */
829
1053
  narrowingAliases(narrows, fn) {
@@ -863,7 +1087,7 @@ export class Lowerer {
863
1087
  * Reachability lowers inits before the declarations they discover, so
864
1088
  * these rebuild after the worklist restores historical shape metadata. */
865
1089
  shapeOrderHelperFinalizers = [];
866
- /** Emit-override specializations (`%C.emit:<event>` — lower-emitter.ts's
1090
+ /** Emit-override specializations (`%C.emit:<event>` — lower-event-emitter.ts's
867
1091
  * emit-overrides block): interned names, the drive-loop queue, and the
868
1092
  * currently-lowering specialization's context (the super-forward
869
1093
  * interception reads it). */
@@ -917,6 +1141,10 @@ export class Lowerer {
917
1141
  * declaration: member reads call the getter (lower-exprs). */
918
1142
  cjsAccessorFns = new Map();
919
1143
  narrowHelpers = new Map();
1144
+ /** Exact members of narrowHelpers produced by narrowedArmHelper. This
1145
+ * lets property consumers recognize an earlier checked extraction by
1146
+ * provenance instead of relying on its generated-name prefix. */
1147
+ checkedNarrowHelpers = new Set();
920
1148
  /** Interned `%iter.drain.<n>` helpers (classIteratorDrainCall): one per
921
1149
  * receiver class — the eager drain of a class iterable's protocol into
922
1150
  * a fresh element array, behind array/call spreads. */
@@ -1130,7 +1358,7 @@ export class Lowerer {
1130
1358
  get ctx() {
1131
1359
  const top = this.fnStack[this.fnStack.length - 1];
1132
1360
  if (!top)
1133
- throw new Error("lowerer bug: no active function context");
1361
+ throw new InternalCompilerError("lowerer bug: no active function context");
1134
1362
  return top;
1135
1363
  }
1136
1364
  get scopes() {
@@ -1377,6 +1605,31 @@ export class Lowerer {
1377
1605
  this.flushDeferred(symbol);
1378
1606
  return symbol;
1379
1607
  }
1608
+ /** Whether this exact direct call belongs to a manifest-validated native
1609
+ * binding. Declaration classification uses this as a probe before normal
1610
+ * expression lowering: resolving must not flush deferred diagnostics or
1611
+ * trigger the merged-namespace fence just because it is asking ownership.
1612
+ * Call lowering remains the authority for every ABI and call-shape
1613
+ * diagnostic once this answers true. */
1614
+ ownsFfiCall(expr) {
1615
+ if (!ts.isIdentifier(expr.expression))
1616
+ return false;
1617
+ const binding = this.ffiImportsByName.get(expr.expression.text);
1618
+ if (binding === undefined || this.ffiBindingSymbols === null)
1619
+ return false;
1620
+ const validSymbols = this.ffiBindingSymbols.get(binding.name);
1621
+ if (validSymbols === undefined)
1622
+ return false;
1623
+ const wasCollecting = this.collecting;
1624
+ this.collecting = true;
1625
+ try {
1626
+ const symbol = this.resolveValueSymbol(expr.expression);
1627
+ return symbol !== null && validSymbols.has(symbol);
1628
+ }
1629
+ finally {
1630
+ this.collecting = wasCollecting;
1631
+ }
1632
+ }
1380
1633
  /** The configured external host module owning an expression's runtime
1381
1634
  * value, or null. Alias chains are followed to their declaration file so
1382
1635
  * direct imports and local re-export facades classify identically. Type
@@ -1983,6 +2236,720 @@ export class Lowerer {
1983
2236
  collectJsonImports(parts) {
1984
2237
  return collectJsonImports(this, parts);
1985
2238
  }
2239
+ /** Discover the unchecked-array values that cross static ABI/storage
2240
+ * boundaries before any function body or module initializer is emitted.
2241
+ * TypeScript's default indexed-access type is a useful source annotation,
2242
+ * but it is not a runtime proof; promoting only the affected slots keeps
2243
+ * the rest of the dense ABI unchanged. */
2244
+ analyzeRuntimeOptionalArrayReads(parts) {
2245
+ const optionalSymbols = new Set();
2246
+ const optionalReturns = new Set();
2247
+ const arithmeticReturns = new Map();
2248
+ const optionalParams = new Map();
2249
+ const optionalFields = new Map();
2250
+ const dynamicObjectEntryRows = new Set();
2251
+ const sourceFiles = parts.map((p) => p.sf);
2252
+ const fnDecls = parts.flatMap((p) => p.fnDecls);
2253
+ // This fixed-point scan intentionally sees deferred bodies before
2254
+ // reachability is known. Batch their binding queries through the
2255
+ // facade's panic fence, then keep lookup free of lowering side effects:
2256
+ // resolveValueSymbol also flushes deferred diagnostics and applies
2257
+ // merged-namespace fences, whose authority remains ordinary lowering.
2258
+ this.checker.prefetchSymbolRoots(sourceFiles);
2259
+ const symbolOf = (node) => {
2260
+ const s = this.checker.getSymbolAtLocation(node);
2261
+ if (!s)
2262
+ return null;
2263
+ return s.flags & ts.SymbolFlags.Alias ? this.checker.getAliasedSymbol(s) : s;
2264
+ };
2265
+ const functionDeclBySymbol = new Map();
2266
+ const signatureBySymbol = new Map();
2267
+ for (const [symbol, sig] of this.fnSigsBySymbol)
2268
+ signatureBySymbol.set(symbol, { params: sig.params, returnType: sig.returnType, top: sig });
2269
+ for (const decl of fnDecls) {
2270
+ const symbol = declSymbolOf(this, decl);
2271
+ if (symbol)
2272
+ functionDeclBySymbol.set(symbol, decl);
2273
+ }
2274
+ for (const sf of sourceFiles) {
2275
+ ts.walkPreorder(sf, (node) => {
2276
+ if ((ts.isMethodDeclaration(node) || ts.isGetAccessorDeclaration(node) || ts.isSetAccessorDeclaration(node)) &&
2277
+ node.body && node.name && (ts.isIdentifier(node.name) || ts.isStringLiteral(node.name))) {
2278
+ const symbol = symbolOf(node.name);
2279
+ if (symbol)
2280
+ functionDeclBySymbol.set(symbol, node);
2281
+ }
2282
+ });
2283
+ }
2284
+ for (const info of this.classes.values()) {
2285
+ for (const { mName, member } of this.classMethodMembers(info)) {
2286
+ if (!member.name || !(ts.isIdentifier(member.name) || ts.isStringLiteral(member.name)))
2287
+ continue;
2288
+ const symbol = symbolOf(member.name);
2289
+ const sig = info.methods.get(mName);
2290
+ if (symbol && sig)
2291
+ signatureBySymbol.set(symbol, { params: sig.params, returnType: sig.ret, method: sig });
2292
+ }
2293
+ }
2294
+ const peel = (node) => {
2295
+ let e = node;
2296
+ while (ts.isParenthesizedExpression(e) || ts.isAsExpression(e) || ts.isTypeAssertion(e) || ts.isNonNullExpression(e)) {
2297
+ e = e.expression;
2298
+ }
2299
+ return e;
2300
+ };
2301
+ const explicitlyNonNull = (node) => {
2302
+ let e = node;
2303
+ while (ts.isParenthesizedExpression(e) || ts.isAsExpression(e) || ts.isTypeAssertion(e) || ts.isNonNullExpression(e)) {
2304
+ if (ts.isNonNullExpression(e))
2305
+ return true;
2306
+ e = e.expression;
2307
+ }
2308
+ return false;
2309
+ };
2310
+ const isArrayRead = (node) => {
2311
+ const e = peel(node);
2312
+ if (!ts.isElementAccessExpression(e))
2313
+ return false;
2314
+ return this.mapTypeOf(this.typeOf(e.expression))?.kind === "array";
2315
+ };
2316
+ const isDynamicObjectEntryRead = (node) => {
2317
+ const read = peel(node);
2318
+ if (!ts.isElementAccessExpression(read) || !ts.isIdentifier(read.expression))
2319
+ return false;
2320
+ const source = symbolOf(read.expression);
2321
+ const declaration = source ? this.checker.valueDeclarationOf(source) : undefined;
2322
+ if (!declaration || !ts.isVariableDeclaration(declaration) || !declaration.initializer)
2323
+ return false;
2324
+ const init = peel(declaration.initializer);
2325
+ if (!ts.isCallExpression(init) || !ts.isPropertyAccessExpression(init.expression))
2326
+ return false;
2327
+ if (init.expression.name.text !== "entries" || !this.isStdlibGlobal(init.expression.expression, "Object"))
2328
+ return false;
2329
+ const object = init.arguments[0];
2330
+ const objectType = object ? this.mapTypeOf(this.typeOf(object)) : null;
2331
+ return objectType?.kind === "dyn" || objectType?.kind === "jsval";
2332
+ };
2333
+ const addUndefined = (t) => {
2334
+ if (t.kind === "union")
2335
+ return this.armTag(t.unionId, UNDEFINED_T) >= 0 ? t : this.withUndefinedArmOf(t) ?? t;
2336
+ if (t.kind === "void" || t.kind === "dyn" || t.kind === "jsval" || t.kind === "generator")
2337
+ return t;
2338
+ return this.withUndefinedArm(t);
2339
+ };
2340
+ const fieldName = (node) => node.name.text;
2341
+ const mayBeOptional = (node) => {
2342
+ // `xs[i]!` is the explicit proven-present form. Its array read keeps
2343
+ // the established dense bounds trap and must not promote the enclosing
2344
+ // function/global ABI to `T | undefined`.
2345
+ if (explicitlyNonNull(node))
2346
+ return false;
2347
+ const e = peel(node);
2348
+ if (isArrayRead(e))
2349
+ return true;
2350
+ if (ts.isCallExpression(e) && this.runtimeOptionalReduceTypes.has(e))
2351
+ return true;
2352
+ if (ts.isCallExpression(e) &&
2353
+ ts.isPropertyAccessExpression(e.expression) &&
2354
+ (e.expression.name.text === "pop" || e.expression.name.text === "shift") &&
2355
+ this.mapTypeOf(this.typeOf(e))?.kind === "union" &&
2356
+ this.armTag(this.mapTypeOf(this.typeOf(e)).unionId, UNDEFINED_T) >= 0)
2357
+ return true;
2358
+ if (ts.isIdentifier(e))
2359
+ return optionalSymbols.has(symbolOf(e) ?? {});
2360
+ if (ts.isCallExpression(e) && ts.isIdentifier(e.expression)) {
2361
+ return optionalReturns.has(symbolOf(e.expression) ?? {});
2362
+ }
2363
+ if (ts.isCallExpression(e) && ts.isPropertyAccessExpression(e.expression)) {
2364
+ return optionalReturns.has(symbolOf(e.expression.name) ?? {});
2365
+ }
2366
+ if (ts.isConditionalExpression(e)) {
2367
+ return mayBeOptional(e.whenTrue) || mayBeOptional(e.whenFalse);
2368
+ }
2369
+ if (ts.isBinaryExpression(e)) {
2370
+ const op = e.operatorToken.kind;
2371
+ if (op === ts.SyntaxKind.AmpersandAmpersandToken ||
2372
+ op === ts.SyntaxKind.BarBarToken ||
2373
+ op === ts.SyntaxKind.QuestionQuestionToken)
2374
+ return mayBeOptional(e.left) || mayBeOptional(e.right);
2375
+ }
2376
+ if (ts.isPropertyAccessExpression(e) && ts.isIdentifier(e.expression)) {
2377
+ const fields = optionalFields.get(symbolOf(e.expression) ?? {});
2378
+ return fields?.has(fieldName(e)) ?? false;
2379
+ }
2380
+ return false;
2381
+ };
2382
+ const optionalStringArithmeticType = (node) => {
2383
+ const e = peel(node);
2384
+ if (!ts.isBinaryExpression(e) || e.operatorToken.kind !== ts.SyntaxKind.PlusToken)
2385
+ return null;
2386
+ const stringArrayRead = (part) => {
2387
+ const t = this.mapTypeOf(this.typeOf(part));
2388
+ const p = peel(part);
2389
+ if (t?.kind !== "string" || !ts.isElementAccessExpression(p))
2390
+ return false;
2391
+ const recv = this.mapTypeOf(this.typeOf(p.expression));
2392
+ return recv?.kind === "array" && recv.elem.kind === "string";
2393
+ };
2394
+ const primitive = (part) => {
2395
+ const t = this.mapTypeOf(this.typeOf(part));
2396
+ return t?.kind === "f64" || t?.kind === "string";
2397
+ };
2398
+ if (!stringArrayRead(e.left) && !stringArrayRead(e.right))
2399
+ return null;
2400
+ if (!(primitive(e.left) || stringArrayRead(e.left)) || !(primitive(e.right) || stringArrayRead(e.right)))
2401
+ return null;
2402
+ return { kind: "union", unionId: this.unions.intern([F64, STRING]) };
2403
+ };
2404
+ const noteField = (decl, name) => {
2405
+ if (!ts.isIdentifier(decl.name))
2406
+ return false;
2407
+ const symbol = symbolOf(decl.name);
2408
+ if (!symbol)
2409
+ return false;
2410
+ return noteFieldSymbol(symbol, name);
2411
+ };
2412
+ const noteFieldSymbol = (symbol, name) => {
2413
+ const set = optionalFields.get(symbol) ?? new Set();
2414
+ const before = set.size;
2415
+ set.add(name);
2416
+ optionalFields.set(symbol, set);
2417
+ return set.size !== before;
2418
+ };
2419
+ const scanPattern = (name, init) => {
2420
+ if (!ts.isArrayBindingPattern(name))
2421
+ return false;
2422
+ const sourceType = this.mapTypeOf(this.typeOf(init));
2423
+ if (sourceType?.kind !== "array")
2424
+ return false;
2425
+ let changed = false;
2426
+ name.elements.forEach((el) => {
2427
+ if (ts.isOmittedExpression(el) || el.name === undefined || el.dotDotDotToken)
2428
+ return;
2429
+ if (ts.isIdentifier(el.name)) {
2430
+ const symbol = symbolOf(el.name);
2431
+ if (symbol && !el.initializer && !optionalSymbols.has(symbol)) {
2432
+ optionalSymbols.add(symbol);
2433
+ // Indexed flow facts can survive a mutating method call in the
2434
+ // checker. The array's element ABI describes every value a
2435
+ // position may hold after that call, so bind from that type.
2436
+ const mapped = sourceType.elem;
2437
+ if (mapped && mapped.kind !== "void" && mapped.kind !== "dyn" && mapped.kind !== "jsval") {
2438
+ const widened = mapped.kind === "union" ? this.withUndefinedArmOf(mapped) : this.withUndefinedArm(mapped);
2439
+ if (widened) {
2440
+ this.runtimeOptionalBindingTypes.set(symbol, widened);
2441
+ const global = this.globalsBySymbol.get(symbol);
2442
+ if (global) {
2443
+ global.type = widened;
2444
+ this.runtimeOptionalGlobals.add(global);
2445
+ }
2446
+ }
2447
+ }
2448
+ changed = true;
2449
+ }
2450
+ }
2451
+ });
2452
+ return changed;
2453
+ };
2454
+ const hofCallbackIndices = (name, hasInitialValue) => {
2455
+ if (name === "reduce" || name === "reduceRight")
2456
+ return hasInitialValue ? [1] : [0, 1];
2457
+ if (name === "map" || name === "filter" || name === "forEach" ||
2458
+ name === "find" || name === "findIndex" || name === "findLast" ||
2459
+ name === "findLastIndex" || name === "some" || name === "every" ||
2460
+ name === "flatMap")
2461
+ return [0];
2462
+ return null;
2463
+ };
2464
+ const bodyReturnsOptional = (fn) => {
2465
+ if (!fn.body)
2466
+ return false;
2467
+ if (!ts.isBlock(fn.body))
2468
+ return mayBeOptional(fn.body);
2469
+ let found = false;
2470
+ ts.walkPreorder(fn.body, (node) => {
2471
+ if (node !== fn.body && (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node) || ts.isMethodDeclaration(node)))
2472
+ return "skip";
2473
+ if (ts.isReturnStatement(node) && node.expression && mayBeOptional(node.expression))
2474
+ found = true;
2475
+ return undefined;
2476
+ });
2477
+ return found;
2478
+ };
2479
+ const promoteHofCallback = (callback, parameterIndices, seen = new Set()) => {
2480
+ let changed = false;
2481
+ const checkerTypeContainsTypeParameter = (type) => {
2482
+ if ((type.flags & ts.TypeFlags.TypeParameter) !== 0)
2483
+ return true;
2484
+ return type.isUnionType() && ts.constituentTypes(type).some(checkerTypeContainsTypeParameter);
2485
+ };
2486
+ const promoteNode = (fn) => {
2487
+ for (const parameterIndex of parameterIndices) {
2488
+ const parameter = fn.parameters[parameterIndex];
2489
+ if (!parameter)
2490
+ continue;
2491
+ const symbol = ts.isIdentifier(parameter.name) ? symbolOf(parameter.name) : null;
2492
+ const checkerType = this.typeOf(parameter.name);
2493
+ const mapped = this.mapTypeOf(checkerType);
2494
+ // Generic callbacks are monomorphized by their call-site binder.
2495
+ // During this prepass the type parameter has no static ABI yet;
2496
+ // asking irTypeOf to invent one poisons otherwise valid generic
2497
+ // value/HOF programs. Leave that parameter at its generic
2498
+ // signature and let the normal instantiation path specialize it.
2499
+ const current = mapped ??
2500
+ (checkerTypeContainsTypeParameter(checkerType) ? null : this.irTypeOf(parameter.name));
2501
+ if (!current)
2502
+ continue;
2503
+ if (!ts.isIdentifier(parameter.name)) {
2504
+ const widened = this.runtimeOptionalType(current);
2505
+ const previous = this.runtimeOptionalPatternTypes.get(parameter.name);
2506
+ this.runtimeOptionalPatternTypes.set(parameter.name, widened);
2507
+ if (!previous || !typeEquals(previous, widened))
2508
+ changed = true;
2509
+ }
2510
+ if (symbol) {
2511
+ const widened = this.runtimeOptionalType(current);
2512
+ const previous = this.runtimeOptionalBindingTypes.get(symbol);
2513
+ this.runtimeOptionalBindingTypes.set(symbol, widened);
2514
+ if (!previous || !typeEquals(previous, widened))
2515
+ changed = true;
2516
+ if (!optionalSymbols.has(symbol)) {
2517
+ optionalSymbols.add(symbol);
2518
+ changed = true;
2519
+ }
2520
+ }
2521
+ }
2522
+ const fnType = this.mapTypeOf(this.typeOf(fn));
2523
+ if (fnType?.kind === "func" && bodyReturnsOptional(fn)) {
2524
+ const widenedReturn = this.runtimeOptionalType(fnType.ret);
2525
+ const previousReturn = this.runtimeOptionalFunctionReturnType(fn, fnType.ret);
2526
+ this.runtimeOptionalFunctionReturns.set(fn, widenedReturn);
2527
+ if (!typeEquals(previousReturn, widenedReturn))
2528
+ changed = true;
2529
+ }
2530
+ };
2531
+ if (ts.isArrowFunction(callback) || ts.isFunctionExpression(callback) || ts.isFunctionDeclaration(callback) || ts.isMethodDeclaration(callback)) {
2532
+ promoteNode(callback);
2533
+ return changed;
2534
+ }
2535
+ const callbackName = ts.isIdentifier(callback)
2536
+ ? callback
2537
+ : ts.isPropertyAccessExpression(callback)
2538
+ ? callback.name
2539
+ : null;
2540
+ if (!callbackName)
2541
+ return false;
2542
+ const symbol = symbolOf(callbackName);
2543
+ if (!symbol || seen.has(symbol))
2544
+ return false;
2545
+ // Generic function values are pinned and monomorphized by the normal
2546
+ // contextual-value path when the HOF lowers its callback. Promoting
2547
+ // their type-parameter body here either asks for an impossible
2548
+ // monomorphic ABI or poisons valid generic value programs.
2549
+ if (this.genericFnsBySymbol.has(symbol))
2550
+ return false;
2551
+ seen.add(symbol);
2552
+ const declaration = this.checker.valueDeclarationOf(symbol);
2553
+ if (declaration && ts.isVariableDeclaration(declaration) && declaration.initializer) {
2554
+ if (promoteHofCallback(peel(declaration.initializer), parameterIndices, seen))
2555
+ changed = true;
2556
+ }
2557
+ const sig = signatureBySymbol.get(symbol);
2558
+ if (sig) {
2559
+ for (const parameterIndex of parameterIndices) {
2560
+ if (!sig.params[parameterIndex])
2561
+ continue;
2562
+ const before = sig.params[parameterIndex].type;
2563
+ sig.params[parameterIndex].type = this.runtimeOptionalType(before);
2564
+ if (!typeEquals(before, sig.params[parameterIndex].type))
2565
+ changed = true;
2566
+ }
2567
+ }
2568
+ const fn = functionDeclBySymbol.get(symbol);
2569
+ if (fn)
2570
+ promoteNode(fn);
2571
+ const valueType = this.runtimeOptionalBindingTypes.get(symbol) ?? this.mapTypeOf(this.typeOf(callback));
2572
+ if (valueType?.kind === "func") {
2573
+ const params = valueType.params.slice();
2574
+ for (const parameterIndex of parameterIndices) {
2575
+ if (params[parameterIndex])
2576
+ params[parameterIndex] = this.runtimeOptionalType(params[parameterIndex]);
2577
+ }
2578
+ const promoted = { ...valueType, params };
2579
+ const previous = this.runtimeOptionalBindingTypes.get(symbol);
2580
+ this.runtimeOptionalBindingTypes.set(symbol, promoted);
2581
+ if (!previous || !typeEquals(previous, promoted))
2582
+ changed = true;
2583
+ const global = this.globalsBySymbol.get(symbol);
2584
+ if (global)
2585
+ global.type = promoted;
2586
+ // A callback-typed parameter used by a native array HOF changes
2587
+ // the containing function's own call ABI. Record that edge in the
2588
+ // already-collected signature as well as on the body binding, so a
2589
+ // caller can promote the concrete callback value it supplies on a
2590
+ // later fixed-point pass (`wrapper(xs, predicate)` ->
2591
+ // `xs.some(predicate)`).
2592
+ if (declaration && ts.isParameter(declaration)) {
2593
+ const owner = declaration.parent;
2594
+ let ownerSymbol = null;
2595
+ if (ts.isFunctionDeclaration(owner))
2596
+ ownerSymbol = declSymbolOf(this, owner) ?? null;
2597
+ else if ((ts.isMethodDeclaration(owner) || ts.isGetAccessorDeclaration(owner) || ts.isSetAccessorDeclaration(owner)) &&
2598
+ owner.name)
2599
+ ownerSymbol = symbolOf(owner.name);
2600
+ const ownerSig = ownerSymbol ? signatureBySymbol.get(ownerSymbol) : undefined;
2601
+ const ownerIndex = ts.isFunctionLike(owner) ? owner.parameters.indexOf(declaration) : -1;
2602
+ const slot = ownerIndex >= 0 ? ownerSig?.params[ownerIndex] : undefined;
2603
+ if (slot && !typeEquals(slot.type, promoted)) {
2604
+ slot.type = promoted;
2605
+ changed = true;
2606
+ }
2607
+ }
2608
+ }
2609
+ return changed;
2610
+ };
2611
+ const callbackReturnsOptional = (callback, seen = new Set()) => {
2612
+ const node = peel(callback);
2613
+ if (ts.isArrowFunction(node) || ts.isFunctionExpression(node))
2614
+ return bodyReturnsOptional(node);
2615
+ const symbol = symbolOf(ts.isPropertyAccessExpression(node) ? node.name : node);
2616
+ if (!symbol || seen.has(symbol))
2617
+ return false;
2618
+ seen.add(symbol);
2619
+ const fn = functionDeclBySymbol.get(symbol);
2620
+ if (fn)
2621
+ return bodyReturnsOptional(fn);
2622
+ const decl = this.checker.valueDeclarationOf(symbol);
2623
+ return !!decl && ts.isVariableDeclaration(decl) && !!decl.initializer && callbackReturnsOptional(decl.initializer, seen);
2624
+ };
2625
+ const scanFile = (sf) => {
2626
+ let changed = false;
2627
+ ts.walkPreorder(sf, (node) => {
2628
+ if (ts.isVariableDeclaration(node)) {
2629
+ if (node.initializer) {
2630
+ if (ts.isIdentifier(node.name) && isDynamicObjectEntryRead(node.initializer)) {
2631
+ const symbol = symbolOf(node.name);
2632
+ if (symbol && !dynamicObjectEntryRows.has(symbol)) {
2633
+ dynamicObjectEntryRows.add(symbol);
2634
+ changed = true;
2635
+ }
2636
+ }
2637
+ else if (ts.isIdentifier(node.name) && mayBeOptional(node.initializer)) {
2638
+ const symbol = symbolOf(node.name);
2639
+ if (symbol && !optionalSymbols.has(symbol)) {
2640
+ optionalSymbols.add(symbol);
2641
+ changed = true;
2642
+ }
2643
+ }
2644
+ if (ts.isIdentifier(node.name)) {
2645
+ const valueSymbol = ts.isIdentifier(peel(node.initializer))
2646
+ ? symbolOf(peel(node.initializer))
2647
+ : ts.isPropertyAccessExpression(peel(node.initializer))
2648
+ ? symbolOf(peel(node.initializer).name)
2649
+ : null;
2650
+ const symbol = symbolOf(node.name);
2651
+ const sourceSig = valueSymbol ? signatureBySymbol.get(valueSymbol) : undefined;
2652
+ const sourceOptional = !!sourceSig &&
2653
+ (optionalReturns.has(valueSymbol) ||
2654
+ (sourceSig.returnType.kind === "union" && this.armTag(sourceSig.returnType.unionId, UNDEFINED_T) >= 0) ||
2655
+ sourceSig.params.some((p) => p.type.kind === "union" && this.armTag(p.type.unionId, UNDEFINED_T) >= 0));
2656
+ if (symbol && valueSymbol && sourceOptional) {
2657
+ const aliasNew = !optionalReturns.has(symbol);
2658
+ if (aliasNew)
2659
+ optionalReturns.add(symbol);
2660
+ if (aliasNew)
2661
+ changed = true;
2662
+ const valueType = this.mapTypeOf(this.typeOf(node.name));
2663
+ if (valueType?.kind === "func" && sourceSig) {
2664
+ const promotedFn = {
2665
+ ...valueType,
2666
+ params: sourceSig.params.map((p) => p.type),
2667
+ ret: sourceSig.returnType,
2668
+ };
2669
+ const previous = this.runtimeOptionalBindingTypes.get(symbol);
2670
+ if (!previous || !typeEquals(previous, promotedFn)) {
2671
+ this.runtimeOptionalBindingTypes.set(symbol, promotedFn);
2672
+ const global = this.globalsBySymbol.get(symbol);
2673
+ if (global)
2674
+ global.type = promotedFn;
2675
+ changed = true;
2676
+ }
2677
+ }
2678
+ }
2679
+ }
2680
+ if (scanPattern(node.name, node.initializer))
2681
+ changed = true;
2682
+ if (ts.isIdentifier(node.name) && ts.isObjectLiteralExpression(peel(node.initializer))) {
2683
+ const object = peel(node.initializer);
2684
+ for (const prop of object.properties) {
2685
+ if (!ts.isPropertyAssignment(prop) && !ts.isShorthandPropertyAssignment(prop))
2686
+ continue;
2687
+ const name = prop.name;
2688
+ if (!name || !(ts.isIdentifier(name) || ts.isStringLiteral(name) || ts.isNumericLiteral(name)))
2689
+ continue;
2690
+ const value = ts.isPropertyAssignment(prop) ? prop.initializer : prop.name;
2691
+ if (mayBeOptional(value) && noteField(node, name.text))
2692
+ changed = true;
2693
+ }
2694
+ }
2695
+ }
2696
+ }
2697
+ if (ts.isBinaryExpression(node) &&
2698
+ (node.operatorToken.kind === ts.SyntaxKind.EqualsToken ||
2699
+ node.operatorToken.kind === ts.SyntaxKind.QuestionQuestionEqualsToken ||
2700
+ node.operatorToken.kind === ts.SyntaxKind.BarBarEqualsToken ||
2701
+ node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandEqualsToken) &&
2702
+ mayBeOptional(node.right)) {
2703
+ if (ts.isIdentifier(node.left)) {
2704
+ const symbol = symbolOf(node.left);
2705
+ if (symbol && !optionalSymbols.has(symbol)) {
2706
+ optionalSymbols.add(symbol);
2707
+ changed = true;
2708
+ }
2709
+ }
2710
+ else if (ts.isPropertyAccessExpression(node.left) && ts.isIdentifier(node.left.expression)) {
2711
+ const symbol = symbolOf(node.left.expression);
2712
+ if (symbol && noteFieldSymbol(symbol, node.left.name.text))
2713
+ changed = true;
2714
+ }
2715
+ }
2716
+ if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression)) {
2717
+ const callbackIndices = hofCallbackIndices(node.expression.name.text, node.arguments.length >= 2);
2718
+ const receiverNode = node.expression.expression;
2719
+ const receiver = this.mapTypeOf(this.typeOf(receiverNode));
2720
+ const callback = callbackIndices === null ? undefined : node.arguments[0];
2721
+ const tuple = receiver?.kind === "record" && this.shapes.get(receiver.shapeId)?.tuple === true;
2722
+ // A JS/evolving-any array may have acquired a precise FLOW type
2723
+ // at this call while its actual binding remains a checked-dynamic
2724
+ // array. Its callback consumes DYN values through runtime method
2725
+ // dispatch, so widening that callback to the native array value
2726
+ // ABI makes it impossible to box back into DYN. Judge a simple
2727
+ // binding by its declaration type, the same storage fact local
2728
+ // declaration lowering uses.
2729
+ let nativeArrayReceiver = receiver?.kind === "array" || tuple;
2730
+ if (nativeArrayReceiver && ts.isIdentifier(receiverNode)) {
2731
+ const receiverSymbol = symbolOf(receiverNode);
2732
+ const declaration = receiverSymbol ? this.checker.valueDeclarationOf(receiverSymbol) : undefined;
2733
+ if (declaration && ts.isVariableDeclaration(declaration)) {
2734
+ const declared = this.mapTypeOf(this.typeOf(declaration.name));
2735
+ if (declared?.kind !== "array" && !(declared?.kind === "record" && this.shapes.get(declared.shapeId)?.tuple === true)) {
2736
+ nativeArrayReceiver = false;
2737
+ }
2738
+ }
2739
+ }
2740
+ if (nativeArrayReceiver && callback && !ts.isSpreadElement(callback)) {
2741
+ if (promoteHofCallback(callback, callbackIndices))
2742
+ changed = true;
2743
+ const method = node.expression.name.text;
2744
+ if ((method === "reduce" || method === "reduceRight") &&
2745
+ (node.arguments.length < 2 || callbackReturnsOptional(callback))) {
2746
+ if (promoteHofCallback(callback, [0, 1]))
2747
+ changed = true;
2748
+ const result = this.runtimeOptionalType(this.irTypeOf(node));
2749
+ const previous = this.runtimeOptionalReduceTypes.get(node);
2750
+ if (!previous || !typeEquals(previous, result)) {
2751
+ this.runtimeOptionalReduceTypes.set(node, result);
2752
+ changed = true;
2753
+ }
2754
+ }
2755
+ }
2756
+ }
2757
+ if (ts.isCallExpression(node) &&
2758
+ (ts.isIdentifier(node.expression) || ts.isPropertyAccessExpression(node.expression))) {
2759
+ const calleeNode = ts.isIdentifier(node.expression) ? node.expression : node.expression.name;
2760
+ const symbol = symbolOf(calleeNode);
2761
+ if (!symbol)
2762
+ return;
2763
+ const sig = signatureBySymbol.get(symbol);
2764
+ if (!sig) {
2765
+ const decl = this.checker.valueDeclarationOf(symbol);
2766
+ if (decl && ts.isVariableDeclaration(decl) && decl.initializer && ts.isIdentifier(decl.initializer)) {
2767
+ const source = symbolOf(decl.initializer);
2768
+ const sourceSig = source ? signatureBySymbol.get(source) : undefined;
2769
+ if (sourceSig) {
2770
+ node.arguments.forEach((arg, i) => {
2771
+ if (ts.isSpreadElement(arg) || !mayBeOptional(arg) || !sourceSig.params[i])
2772
+ return;
2773
+ const before = sourceSig.params[i].type;
2774
+ sourceSig.params[i].type = this.runtimeOptionalType(before);
2775
+ if (!typeEquals(before, sourceSig.params[i].type)) {
2776
+ changed = true;
2777
+ const sourceFn = functionDeclBySymbol.get(source);
2778
+ const parameter = sourceFn?.parameters[i];
2779
+ if (parameter) {
2780
+ for (const bound of boundIdentifiersOf(parameter.name)) {
2781
+ const boundSymbol = symbolOf(bound);
2782
+ if (boundSymbol && !optionalSymbols.has(boundSymbol)) {
2783
+ optionalSymbols.add(boundSymbol);
2784
+ changed = true;
2785
+ }
2786
+ }
2787
+ }
2788
+ }
2789
+ });
2790
+ }
2791
+ }
2792
+ return;
2793
+ }
2794
+ node.arguments.forEach((arg, i) => {
2795
+ const callbackSlot = sig.params[i]?.type;
2796
+ if (callbackSlot?.kind === "func" && !ts.isSpreadElement(arg)) {
2797
+ const optionalCallbackParams = callbackSlot.params.flatMap((type, index) => type.kind === "union" && this.armTag(type.unionId, UNDEFINED_T) >= 0 ? [index] : []);
2798
+ if (optionalCallbackParams.length > 0 && promoteHofCallback(arg, optionalCallbackParams)) {
2799
+ changed = true;
2800
+ }
2801
+ }
2802
+ if (ts.isSpreadElement(arg) || !mayBeOptional(arg) || !sig.params[i])
2803
+ return;
2804
+ const set = optionalParams.get(symbol) ?? new Set();
2805
+ const before = set.size;
2806
+ set.add(i);
2807
+ optionalParams.set(symbol, set);
2808
+ if (set.size !== before) {
2809
+ changed = true;
2810
+ const callee = functionDeclBySymbol.get(symbol);
2811
+ const parameter = callee?.parameters[i];
2812
+ if (parameter) {
2813
+ for (const bound of boundIdentifiersOf(parameter.name)) {
2814
+ const boundSymbol = symbolOf(bound);
2815
+ if (boundSymbol && !optionalSymbols.has(boundSymbol)) {
2816
+ optionalSymbols.add(boundSymbol);
2817
+ changed = true;
2818
+ }
2819
+ }
2820
+ }
2821
+ }
2822
+ });
2823
+ }
2824
+ });
2825
+ return changed;
2826
+ };
2827
+ const scanReturns = (symbol, decl) => {
2828
+ if (!decl.body)
2829
+ return false;
2830
+ let changed = false;
2831
+ if (!ts.isBlock(decl.body) && mayBeOptional(decl.body) && !optionalReturns.has(symbol)) {
2832
+ optionalReturns.add(symbol);
2833
+ changed = true;
2834
+ }
2835
+ if (!ts.isBlock(decl.body)) {
2836
+ const arithmetic = optionalStringArithmeticType(decl.body);
2837
+ if (arithmetic && !arithmeticReturns.has(symbol)) {
2838
+ arithmeticReturns.set(symbol, arithmetic);
2839
+ changed = true;
2840
+ }
2841
+ }
2842
+ ts.walkPreorder(decl.body, (node) => {
2843
+ if (node !== decl.body && (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node) || ts.isMethodDeclaration(node)))
2844
+ return "skip";
2845
+ if (ts.isReturnStatement(node) && node.expression && mayBeOptional(node.expression) && !optionalReturns.has(symbol)) {
2846
+ optionalReturns.add(symbol);
2847
+ changed = true;
2848
+ }
2849
+ if (ts.isReturnStatement(node) && node.expression) {
2850
+ const arithmetic = optionalStringArithmeticType(node.expression);
2851
+ if (arithmetic && !arithmeticReturns.has(symbol)) {
2852
+ arithmeticReturns.set(symbol, arithmetic);
2853
+ changed = true;
2854
+ }
2855
+ }
2856
+ return undefined;
2857
+ });
2858
+ return changed;
2859
+ };
2860
+ let changed = true;
2861
+ while (changed) {
2862
+ changed = false;
2863
+ for (const sf of sourceFiles)
2864
+ if (scanFile(sf))
2865
+ changed = true;
2866
+ for (const [symbol, decl] of functionDeclBySymbol)
2867
+ if (scanReturns(symbol, decl))
2868
+ changed = true;
2869
+ }
2870
+ for (const [symbol, sig] of signatureBySymbol) {
2871
+ const params = optionalParams.get(symbol);
2872
+ if (params) {
2873
+ for (const i of params) {
2874
+ const shape = sig.params[i];
2875
+ if (shape)
2876
+ shape.type = addUndefined(shape.type);
2877
+ }
2878
+ }
2879
+ if (optionalReturns.has(symbol)) {
2880
+ const next = sig.returnType.kind === "promise"
2881
+ ? { kind: "promise", inner: addUndefined(sig.returnType.inner) }
2882
+ : addUndefined(sig.returnType);
2883
+ sig.returnType = next;
2884
+ if (sig.top)
2885
+ sig.top.returnType = next;
2886
+ if (sig.method)
2887
+ sig.method.ret = next;
2888
+ }
2889
+ const arithmetic = arithmeticReturns.get(symbol);
2890
+ if (arithmetic && sig.returnType.kind !== "promise") {
2891
+ sig.returnType = arithmetic;
2892
+ if (sig.top)
2893
+ sig.top.returnType = arithmetic;
2894
+ if (sig.method)
2895
+ sig.method.ret = arithmetic;
2896
+ const decl = functionDeclBySymbol.get(symbol);
2897
+ if (decl)
2898
+ this.runtimeOptionalFunctionReturns.set(decl, arithmetic);
2899
+ }
2900
+ }
2901
+ for (const sf of sourceFiles) {
2902
+ ts.walkPreorder(sf, (node) => {
2903
+ if (!ts.isVariableDeclaration(node) || !ts.isIdentifier(node.name))
2904
+ return;
2905
+ const symbol = symbolOf(node.name);
2906
+ if (!symbol)
2907
+ return;
2908
+ const fields = optionalFields.get(symbol);
2909
+ if (!dynamicObjectEntryRows.has(symbol) && !optionalSymbols.has(symbol) && !fields)
2910
+ return;
2911
+ const current = this.mapTypeOf(this.typeOf(node.name));
2912
+ if (!current)
2913
+ return;
2914
+ let promoted = dynamicObjectEntryRows.has(symbol) ? DYN : current;
2915
+ if (!dynamicObjectEntryRows.has(symbol) && optionalSymbols.has(symbol))
2916
+ promoted = addUndefined(promoted);
2917
+ if (promoted.kind === "func" && node.initializer && ts.isIdentifier(node.initializer)) {
2918
+ const sourceSig = this.fnSigOf(node.initializer);
2919
+ if (sourceSig) {
2920
+ promoted = {
2921
+ ...promoted,
2922
+ params: sourceSig.params.filter((p) => p.mode !== "dynRest").map((p) => p.type),
2923
+ ret: sourceSig.returnType,
2924
+ };
2925
+ }
2926
+ }
2927
+ if (fields && promoted.kind === "record") {
2928
+ for (const field of fields) {
2929
+ const source = promoted.kind === "record"
2930
+ ? this.shapes.get(promoted.shapeId)?.fields.find((f) => f.name === field)
2931
+ : undefined;
2932
+ if (!source)
2933
+ continue;
2934
+ promoted = this.runtimeOptionalRecordField(promoted, field, addUndefined(source.type));
2935
+ }
2936
+ }
2937
+ if (!typeEquals(promoted, current)) {
2938
+ this.runtimeOptionalBindingTypes.set(symbol, promoted);
2939
+ const global = ts.isIdentifier(node.name) ? this.globalOf(node.name) : this.globalsBySymbol.get(symbol);
2940
+ if (global) {
2941
+ global.type = promoted;
2942
+ this.runtimeOptionalGlobals.add(global);
2943
+ }
2944
+ }
2945
+ else if (promoted.kind === "union" && this.armTag(promoted.unionId, UNDEFINED_T) >= 0) {
2946
+ const global = ts.isIdentifier(node.name) ? this.globalOf(node.name) : this.globalsBySymbol.get(symbol);
2947
+ if (global)
2948
+ this.runtimeOptionalGlobals.add(global);
2949
+ }
2950
+ });
2951
+ }
2952
+ }
1986
2953
  run() {
1987
2954
  const parts = this.splitFiles();
1988
2955
  // The coverage remainder deliberately visits every body that reachable
@@ -1996,6 +2963,7 @@ export class Lowerer {
1996
2963
  this.checker.prefetchSourceFile(fp.sf);
1997
2964
  }
1998
2965
  this.collectProgram(parts);
2966
+ this.analyzeRuntimeOptionalArrayReads(parts);
1999
2967
  // Decorated classes analyze AFTER the whole collection pass: a
2000
2968
  // decorator's return type may name a subclass declared below the
2001
2969
  // class, and reference lowering needs each class's rebindability
@@ -2224,7 +3192,7 @@ export class Lowerer {
2224
3192
  const module = this.diags.length > 0
2225
3193
  ? null
2226
3194
  : {
2227
- irVersion: 6,
3195
+ irVersion: 8,
2228
3196
  sourceFile: this.entry.fileName,
2229
3197
  functions,
2230
3198
  classes: artifacts.classes,
@@ -2367,6 +3335,7 @@ export class Lowerer {
2367
3335
  // will reuse the same answers later.
2368
3336
  this.prefetchClassCollection(parts.flatMap((fp) => fp.classDecls));
2369
3337
  this.collectProgram(parts);
3338
+ this.analyzeRuntimeOptionalArrayReads(parts);
2370
3339
  // Decorated classes analyze post-collection here too: the %init seeds
2371
3340
  // lower the decoration calls, whose edges (decorator bodies, construct
2372
3341
  // thunks) reachable emit must see.
@@ -2710,7 +3679,61 @@ export class Lowerer {
2710
3679
  moduleArtifacts(functions) {
2711
3680
  return moduleArtifacts(this, functions);
2712
3681
  }
2713
- /* ── diagnostics plumbing ─────────────────────────────────────────── */
3682
+ deferToRuntimeFence(diagsBefore, node, target) {
3683
+ if ((this.diagSink !== null && target.allowDiagSink !== true) ||
3684
+ (this.diags.length <= diagsBefore && target.fallback === undefined)) {
3685
+ return null;
3686
+ }
3687
+ const captured = this.diags.splice(diagsBefore);
3688
+ if (captured.some((d) => d.code === "SC9001")) {
3689
+ this.diags.push(...captured);
3690
+ return null;
3691
+ }
3692
+ this.runtimeFences.push(...captured);
3693
+ const first = captured[0];
3694
+ const loc = locOf(node);
3695
+ const code = first?.code ?? target.fallback.code;
3696
+ const baseMessage = first?.message ?? target.fallback.message;
3697
+ const messageLoc = first?.loc ?? loc;
3698
+ const source = first
3699
+ ? this.program.getSourceFile(messageLoc.file) ?? node.getSourceFile()
3700
+ : node.getSourceFile();
3701
+ const pos = ts.getLineAndCharacterOfPosition(source, messageLoc.start);
3702
+ const fence = {
3703
+ kind: "runtimeFence",
3704
+ code,
3705
+ message: target.bareMessage
3706
+ ? baseMessage
3707
+ : `${baseMessage} [${code} at ${messageLoc.file}:${pos.line + 1}]`,
3708
+ loc,
3709
+ };
3710
+ if (target.kind === "statement")
3711
+ return fence;
3712
+ const params = target.params ?? [];
3713
+ const name = typeof target.name === "function" ? target.name() : target.name;
3714
+ const fn = {
3715
+ name,
3716
+ params,
3717
+ returnType: target.returnType,
3718
+ locals: params.map((p) => ({
3719
+ id: p.localId,
3720
+ name: p.name,
3721
+ type: p.type,
3722
+ mutable: target.paramsMutable ?? false,
3723
+ })),
3724
+ body: [fence],
3725
+ loc,
3726
+ };
3727
+ if (target.async)
3728
+ fn.async = true;
3729
+ if (target.generator)
3730
+ fn.generator = target.generator;
3731
+ if (target.kind === "function")
3732
+ return fn;
3733
+ fn.captures = [];
3734
+ this.liftedFns.push(fn);
3735
+ return { kind: "closure", fnName: fn.name, captures: [], type: target.type, loc };
3736
+ }
2714
3737
  /** All diagnostics land here; while a generic instance body is lowering,
2715
3738
  * the instantiation context is appended so the user knows which concrete
2716
3739
  * types made the (source-anchored) construct fail. */
@@ -3112,11 +4135,14 @@ export class Lowerer {
3112
4135
  const def = this.unions.get(unionId);
3113
4136
  return def ? def.arms.flatMap((arm, tag) => (this.isArrayValueType(arm) ? [tag] : [])) : [];
3114
4137
  }
3115
- /** isJsonSafeType with this Lowerer's registries — the shared fence for
3116
- * what JSON.stringify accepts and what a checked cast can validate. */
4138
+ /** Checked JSON conversion excludes undefined array slots because JSON
4139
+ * text cannot preserve that distinction. */
3117
4140
  jsonSafe(t) {
3118
4141
  return isJsonSafeType(t, (id) => this.shapes.get(id), (id) => this.unions.get(id));
3119
4142
  }
4143
+ jsonStringifySafe(t) {
4144
+ return isJsonStringifySafeType(t, (id) => this.shapes.get(id), (id) => this.unions.get(id));
4145
+ }
3120
4146
  /** True when a type is a BARE undefined-armed union — the one JSON-unsafe
3121
4147
  * shape whose rejections deserve their own wording: Node's stringify of
3122
4148
  * bare undefined is not a string at all and JSON text never matches the
@@ -3316,7 +4342,7 @@ export class Lowerer {
3316
4342
  /** Unwraps a HYBRID (function-with-properties) record to its callable:
3317
4343
  * a record whose shape carries the reserved `%call` func field reads
3318
4344
  * that field; anything else returns unchanged. The consumer half of
3319
- * types.ts's chalk-shape mapping — call paths and func-slot coercions
4345
+ * type-mapper.ts's chalk-shape mapping — call paths and func-slot coercions
3320
4346
  * share it. */
3321
4347
  hybridCallUnwrap(expr) {
3322
4348
  if (expr.type.kind !== "record")
@@ -3499,7 +4525,7 @@ export class Lowerer {
3499
4525
  }
3500
4526
  // A HYBRID (function-with-properties) record flowing into a plain
3501
4527
  // func slot extracts its reserved %call field — the chalk shape's
3502
- // "the value IS callable" half (types.ts's hybrid mapping).
4528
+ // "the value IS callable" half (type-mapper.ts's hybrid mapping).
3503
4529
  if (expected.kind === "func" && expr.type.kind === "record") {
3504
4530
  const un = this.hybridCallUnwrap(expr);
3505
4531
  if (un !== expr && typeEquals(un.type, expected))
@@ -3954,102 +4980,102 @@ export class Lowerer {
3954
4980
  return value;
3955
4981
  case "wrap": {
3956
4982
  if (dst.kind !== "union")
3957
- throw new Error("lowerer bug: wrap lift against a non-union");
4983
+ throw new InternalCompilerError("lowerer bug: wrap lift against a non-union");
3958
4984
  return { kind: "unionWrap", unionId: dst.unionId, tag: lift.tag, value, type: dst, loc };
3959
4985
  }
3960
4986
  case "retag": {
3961
4987
  if (dst.kind !== "union" || value.type.kind !== "union")
3962
- throw new Error("lowerer bug: retag lift shape");
4988
+ throw new InternalCompilerError("lowerer bug: retag lift shape");
3963
4989
  const retag = this.unionRetagHelper(value.type.unionId, dst.unionId, loc);
3964
4990
  if (!retag)
3965
- throw new Error("lowerer bug: planned retag lift failed to intern");
4991
+ throw new InternalCompilerError("lowerer bug: planned retag lift failed to intern");
3966
4992
  return { kind: "call", callee: retag, args: [value], type: dst, loc };
3967
4993
  }
3968
4994
  case "liftWrap": {
3969
4995
  if (dst.kind !== "union")
3970
- throw new Error("lowerer bug: liftWrap lift against a non-union");
4996
+ throw new InternalCompilerError("lowerer bug: liftWrap lift against a non-union");
3971
4997
  const inner = this.widthLiftPlan(value.type, lift.arm);
3972
4998
  if (!inner)
3973
- throw new Error("lowerer bug: planned liftWrap arm stopped lifting");
4999
+ throw new InternalCompilerError("lowerer bug: planned liftWrap arm stopped lifting");
3974
5000
  const lifted = this.applyWidthLift(inner, value, lift.arm, loc);
3975
5001
  return { kind: "unionWrap", unionId: dst.unionId, tag: lift.tag, value: lifted, type: dst, loc };
3976
5002
  }
3977
5003
  case "width": {
3978
5004
  if (dst.kind !== "record" || value.type.kind !== "record")
3979
- throw new Error("lowerer bug: width lift shape");
5005
+ throw new InternalCompilerError("lowerer bug: width lift shape");
3980
5006
  const helper = this.recordWidthHelper(value.type.shapeId, dst.shapeId, loc);
3981
5007
  if (!helper)
3982
- throw new Error("lowerer bug: planned width lift failed to intern");
5008
+ throw new InternalCompilerError("lowerer bug: planned width lift failed to intern");
3983
5009
  return { kind: "call", callee: helper, args: [value], type: dst, loc };
3984
5010
  }
3985
5011
  case "arr": {
3986
5012
  if (dst.kind !== "array" || value.type.kind !== "array")
3987
- throw new Error("lowerer bug: arr lift shape");
5013
+ throw new InternalCompilerError("lowerer bug: arr lift shape");
3988
5014
  const helper = this.arrayWidthHelper(value.type, dst, loc);
3989
5015
  if (!helper)
3990
- throw new Error("lowerer bug: planned arr lift failed to intern");
5016
+ throw new InternalCompilerError("lowerer bug: planned arr lift failed to intern");
3991
5017
  return { kind: "call", callee: helper, args: [value], type: dst, loc };
3992
5018
  }
3993
5019
  case "tupleArr": {
3994
5020
  if (dst.kind !== "array" || value.type.kind !== "record")
3995
- throw new Error("lowerer bug: tupleArr lift shape");
5021
+ throw new InternalCompilerError("lowerer bug: tupleArr lift shape");
3996
5022
  const helper = this.tupleArrayWidthHelper(value.type.shapeId, dst, loc);
3997
5023
  if (!helper)
3998
- throw new Error("lowerer bug: planned tupleArr lift failed to intern");
5024
+ throw new InternalCompilerError("lowerer bug: planned tupleArr lift failed to intern");
3999
5025
  return { kind: "call", callee: helper, args: [value], type: dst, loc };
4000
5026
  }
4001
5027
  case "emptyArr": {
4002
5028
  if (dst.kind !== "array" || value.type.kind !== "array")
4003
- throw new Error("lowerer bug: emptyArr lift shape");
5029
+ throw new InternalCompilerError("lowerer bug: emptyArr lift shape");
4004
5030
  const helper = this.emptyArrayLiftHelper(value.type, dst, loc);
4005
5031
  return { kind: "call", callee: helper, args: [value], type: dst, loc };
4006
5032
  }
4007
5033
  case "objWidth": {
4008
5034
  if (dst.kind !== "record" || value.type.kind !== "object")
4009
- throw new Error("lowerer bug: objWidth lift shape");
5035
+ throw new InternalCompilerError("lowerer bug: objWidth lift shape");
4010
5036
  const helper = this.objRecordWidthHelper(value.type.className, dst.shapeId, loc);
4011
5037
  if (!helper)
4012
- throw new Error("lowerer bug: planned objWidth lift failed to intern");
5038
+ throw new InternalCompilerError("lowerer bug: planned objWidth lift failed to intern");
4013
5039
  return { kind: "call", callee: helper, args: [value], type: dst, loc };
4014
5040
  }
4015
5041
  case "clsWidth": {
4016
5042
  if (dst.kind !== "object" || value.type.kind !== "record")
4017
- throw new Error("lowerer bug: clsWidth lift shape");
5043
+ throw new InternalCompilerError("lowerer bug: clsWidth lift shape");
4018
5044
  const helper = this.recordClassWidthHelper(value.type.shapeId, dst.className, loc);
4019
5045
  if (!helper)
4020
- throw new Error("lowerer bug: planned clsWidth lift failed to intern");
5046
+ throw new InternalCompilerError("lowerer bug: planned clsWidth lift failed to intern");
4021
5047
  return { kind: "call", callee: helper, args: [value], type: dst, loc };
4022
5048
  }
4023
5049
  case "narrow": {
4024
5050
  if (value.type.kind !== "union")
4025
- throw new Error("lowerer bug: narrow lift on a non-union");
5051
+ throw new InternalCompilerError("lowerer bug: narrow lift on a non-union");
4026
5052
  const helper = this.narrowedArmHelper(value.type.unionId, dst, loc);
4027
5053
  if (!helper)
4028
- throw new Error("lowerer bug: planned narrow lift failed to intern");
5054
+ throw new InternalCompilerError("lowerer bug: planned narrow lift failed to intern");
4029
5055
  return { kind: "call", callee: helper, args: [value], type: dst, loc };
4030
5056
  }
4031
5057
  case "dynIn": {
4032
5058
  if (dst.kind !== "dyn")
4033
- throw new Error("lowerer bug: dynIn lift against a non-dyn slot");
5059
+ throw new InternalCompilerError("lowerer bug: dynIn lift against a non-dyn slot");
4034
5060
  return { kind: "dynFrom", value, type: DYN, loc };
4035
5061
  }
4036
5062
  case "upcast": {
4037
5063
  if (dst.kind !== "object" || value.type.kind !== "object")
4038
- throw new Error("lowerer bug: upcast lift shape");
5064
+ throw new InternalCompilerError("lowerer bug: upcast lift shape");
4039
5065
  return this.upcastTo(value, dst.className);
4040
5066
  }
4041
5067
  case "funcAdapt": {
4042
5068
  if (dst.kind !== "func" || value.type.kind !== "func")
4043
- throw new Error("lowerer bug: funcAdapt lift shape");
5069
+ throw new InternalCompilerError("lowerer bug: funcAdapt lift shape");
4044
5070
  const adapter = this.funcCoerceAdapter(value.type, dst, loc);
4045
5071
  if (!adapter)
4046
- throw new Error("lowerer bug: planned funcAdapt lift failed to intern");
5072
+ throw new InternalCompilerError("lowerer bug: planned funcAdapt lift failed to intern");
4047
5073
  return { kind: "call", callee: adapter, args: [value], type: dst, loc };
4048
5074
  }
4049
5075
  default: {
4050
5076
  const _exhaustive = lift;
4051
5077
  void _exhaustive;
4052
- throw new Error("unreachable");
5078
+ throw new InternalCompilerError("unreachable");
4053
5079
  }
4054
5080
  }
4055
5081
  }
@@ -4264,7 +5290,7 @@ export class Lowerer {
4264
5290
  }
4265
5291
  if ("absent" in lift) {
4266
5292
  if (f.type.kind !== "union")
4267
- throw new Error("lowerer bug: absent lift against a non-union field");
5293
+ throw new InternalCompilerError("lowerer bug: absent lift against a non-union field");
4268
5294
  // The unset optional field: build the undefined arm.
4269
5295
  return {
4270
5296
  name: f.name,
@@ -4406,8 +5432,6 @@ export class Lowerer {
4406
5432
  this.widthHelpers.set(key, name);
4407
5433
  const arrT = { kind: "array", elem: fromElem };
4408
5434
  const outT = { kind: "array", elem: toElem };
4409
- const ref = (localId, type) => ({ kind: "varRef", localId, type, loc });
4410
- const num = (value) => ({ kind: "numLit", value, type: { kind: "f64" }, loc });
4411
5435
  const f64 = { kind: "f64" };
4412
5436
  this.liftedFns.push({
4413
5437
  name,
@@ -4424,17 +5448,17 @@ export class Lowerer {
4424
5448
  {
4425
5449
  kind: "varDecl",
4426
5450
  localId: "n.0",
4427
- init: { kind: "arrIntrinsic", method: "length", receiver: ref("a.0", arrT), args: [], type: f64, loc },
5451
+ init: { kind: "arrIntrinsic", method: "length", receiver: varRef("a.0", arrT, loc), args: [], type: f64, loc },
4428
5452
  loc,
4429
5453
  },
4430
5454
  {
4431
5455
  kind: "for",
4432
- init: { kind: "varDecl", localId: "i.0", init: num(0), loc },
4433
- cond: { kind: "bin", op: "<", left: ref("i.0", f64), right: ref("n.0", f64), type: BOOL, loc },
5456
+ init: { kind: "varDecl", localId: "i.0", init: numLit(0, loc), loc },
5457
+ cond: { kind: "bin", op: "<", left: varRef("i.0", f64, loc), right: varRef("n.0", f64, loc), type: BOOL, loc },
4434
5458
  update: {
4435
5459
  kind: "assign",
4436
5460
  localId: "i.0",
4437
- value: { kind: "bin", op: "+", left: ref("i.0", f64), right: num(1), type: f64, loc },
5461
+ value: { kind: "bin", op: "+", left: varRef("i.0", f64, loc), right: numLit(1, loc), type: f64, loc },
4438
5462
  loc,
4439
5463
  },
4440
5464
  body: [
@@ -4443,9 +5467,9 @@ export class Lowerer {
4443
5467
  expr: {
4444
5468
  kind: "arrIntrinsic",
4445
5469
  method: "push",
4446
- receiver: ref("out.0", outT),
5470
+ receiver: varRef("out.0", outT, loc),
4447
5471
  args: [
4448
- this.applyWidthLift(elemLift, { kind: "arrayGet", arr: ref("a.0", arrT), index: ref("i.0", f64), type: fromElem, loc }, toElem, loc),
5472
+ this.applyWidthLift(elemLift, { kind: "arrayGet", arr: varRef("a.0", arrT, loc), index: varRef("i.0", f64, loc), type: fromElem, loc }, toElem, loc),
4449
5473
  ],
4450
5474
  type: f64,
4451
5475
  loc,
@@ -4455,7 +5479,7 @@ export class Lowerer {
4455
5479
  ],
4456
5480
  loc,
4457
5481
  },
4458
- { kind: "return", value: ref("out.0", outT), loc },
5482
+ { kind: "return", value: varRef("out.0", outT, loc), loc },
4459
5483
  ],
4460
5484
  loc,
4461
5485
  });
@@ -4554,7 +5578,7 @@ export class Lowerer {
4554
5578
  const lift = plan.get(f.name);
4555
5579
  if ("absent" in lift) {
4556
5580
  if (f.type.kind !== "union")
4557
- throw new Error("lowerer bug: absent lift against a non-union field");
5581
+ throw new InternalCompilerError("lowerer bug: absent lift against a non-union field");
4558
5582
  return {
4559
5583
  name: f.name,
4560
5584
  value: {
@@ -4683,7 +5707,7 @@ export class Lowerer {
4683
5707
  if ("absent" in entry) {
4684
5708
  const u = this.wrappedUndefined(shape.type, loc);
4685
5709
  if (!u)
4686
- throw new Error("lowerer bug: planned absent ctor arg has no undefined arm");
5710
+ throw new InternalCompilerError("lowerer bug: planned absent ctor arg has no undefined arm");
4687
5711
  return u;
4688
5712
  }
4689
5713
  const get = { kind: "recordGet", obj: r, shapeId: fromId, field: entry.field, type: entry.src, loc };
@@ -4986,7 +6010,7 @@ export class Lowerer {
4986
6010
  const aRef = { kind: "varRef", localId: `a.${i}`, type: toT.params[i], loc };
4987
6011
  const converted = this.coerceToExpected(aRef, pt);
4988
6012
  if (!typeEquals(converted.type, pt))
4989
- throw new Error("lowerer bug: probed fn-adapter param stopped coercing");
6013
+ throw new InternalCompilerError("lowerer bug: probed fn-adapter param stopped coercing");
4990
6014
  return converted;
4991
6015
  });
4992
6016
  const call = {
@@ -5029,7 +6053,7 @@ export class Lowerer {
5029
6053
  else {
5030
6054
  const result = this.coerceToExpected(call, toT.ret);
5031
6055
  if (!typeEquals(result.type, toT.ret))
5032
- throw new Error("lowerer bug: probed fn-adapter return stopped coercing");
6056
+ throw new InternalCompilerError("lowerer bug: probed fn-adapter return stopped coercing");
5033
6057
  body = [{ kind: "return", value: result, loc }];
5034
6058
  }
5035
6059
  }
@@ -5519,10 +6543,13 @@ export class Lowerer {
5519
6543
  return null;
5520
6544
  const key = `${fromId}:${tag}`;
5521
6545
  const existing = this.narrowHelpers.get(key);
5522
- if (existing)
6546
+ if (existing) {
6547
+ this.checkedNarrowHelpers.add(existing);
5523
6548
  return existing;
6549
+ }
5524
6550
  const name = `%union.narrow.${this.narrowHelpers.size}`;
5525
6551
  this.narrowHelpers.set(key, name);
6552
+ this.checkedNarrowHelpers.add(name);
5526
6553
  const fromT = { kind: "union", unionId: fromId };
5527
6554
  const u = { kind: "varRef", localId: "u.0", type: fromT, loc };
5528
6555
  const body = [];
@@ -5720,7 +6747,7 @@ export class Lowerer {
5720
6747
  if (e.type.kind === "dyn" || e.type.kind === "func") {
5721
6748
  return { kind: "jsMarshal", value: e, type: JSVAL, loc };
5722
6749
  }
5723
- throw new Error(`lowerer bug: jsvalLiftExpr of unliftable ${e.type.kind}`);
6750
+ throw new InternalCompilerError(`lowerer bug: jsvalLiftExpr of unliftable ${e.type.kind}`);
5724
6751
  }
5725
6752
  /** Interned `%jsin.union.<n>(u)` — the runtime tag switch marshaling a
5726
6753
  * union value INTO the island: unit arms become the engine's own
@@ -5737,7 +6764,7 @@ export class Lowerer {
5737
6764
  return existing;
5738
6765
  const def = this.unions.get(unionId);
5739
6766
  if (!def)
5740
- throw new Error(`lowerer bug: jsval lift of unknown union ${unionId}`);
6767
+ throw new InternalCompilerError(`lowerer bug: jsval lift of unknown union ${unionId}`);
5741
6768
  const name = `%jsin.union.${this.jsinHelpers.size}`;
5742
6769
  this.jsinHelpers.set(key, name);
5743
6770
  const fromT = { kind: "union", unionId };
@@ -5779,7 +6806,7 @@ export class Lowerer {
5779
6806
  return existing;
5780
6807
  const shape = this.shapes.get(shapeId);
5781
6808
  if (!shape)
5782
- throw new Error(`lowerer bug: jsval lift of unknown shape ${shapeId}`);
6809
+ throw new InternalCompilerError(`lowerer bug: jsval lift of unknown shape ${shapeId}`);
5783
6810
  const name = `%jsin.rec.${this.jsinHelpers.size}`;
5784
6811
  this.jsinHelpers.set(key, name);
5785
6812
  const recT = { kind: "record", shapeId };
@@ -5812,9 +6839,7 @@ export class Lowerer {
5812
6839
  const iv = shape.indexValue;
5813
6840
  const f64 = { kind: "f64" };
5814
6841
  const ksT = arrayOf(STRING);
5815
- const ref = (localId, type) => ({ kind: "varRef", localId, type, loc });
5816
- const num = (value) => ({ kind: "numLit", value, type: f64, loc });
5817
- const kRef = ref("k.0", STRING);
6842
+ const kRef = varRef("k.0", STRING, loc);
5818
6843
  this.liftedFns.push({
5819
6844
  name,
5820
6845
  params: [{ localId: "r.0", name: "r", type: recT }],
@@ -5831,25 +6856,25 @@ export class Lowerer {
5831
6856
  { kind: "varDecl", localId: "ks.0", init: { kind: "recordOvfKeys", obj: r, shapeId, type: ksT, loc }, loc },
5832
6857
  {
5833
6858
  kind: "for",
5834
- init: { kind: "varDecl", localId: "i.0", init: num(0), loc },
6859
+ init: { kind: "varDecl", localId: "i.0", init: numLit(0, loc), loc },
5835
6860
  cond: {
5836
6861
  kind: "bin",
5837
6862
  op: "<",
5838
- left: ref("i.0", f64),
5839
- right: { kind: "arrIntrinsic", method: "length", receiver: ref("ks.0", ksT), args: [], type: f64, loc },
6863
+ left: varRef("i.0", f64, loc),
6864
+ right: { kind: "arrIntrinsic", method: "length", receiver: varRef("ks.0", ksT, loc), args: [], type: f64, loc },
5840
6865
  type: BOOL,
5841
6866
  loc,
5842
6867
  },
5843
- update: { kind: "assign", localId: "i.0", value: { kind: "bin", op: "+", left: ref("i.0", f64), right: num(1), type: f64, loc }, loc },
6868
+ update: { kind: "assign", localId: "i.0", value: { kind: "bin", op: "+", left: varRef("i.0", f64, loc), right: numLit(1, loc), type: f64, loc }, loc },
5844
6869
  body: [
5845
- { kind: "varDecl", localId: "k.0", init: { kind: "arrayGet", arr: ref("ks.0", ksT), index: ref("i.0", f64), type: STRING, loc }, loc },
6870
+ { kind: "varDecl", localId: "k.0", init: { kind: "arrayGet", arr: varRef("ks.0", ksT, loc), index: varRef("i.0", f64, loc), type: STRING, loc }, loc },
5846
6871
  {
5847
6872
  kind: "exprStmt",
5848
6873
  expr: {
5849
6874
  kind: "jsOp",
5850
6875
  op: "setIdx",
5851
6876
  args: [
5852
- ref("out.0", JSVAL),
6877
+ varRef("out.0", JSVAL, loc),
5853
6878
  { kind: "jsMarshal", value: kRef, type: JSVAL, loc },
5854
6879
  this.jsvalLiftExpr({ kind: "recordKeyGet", obj: r, shapeId, key: kRef, overflowOnly: true, type: iv, loc }, loc),
5855
6880
  ],
@@ -5861,7 +6886,7 @@ export class Lowerer {
5861
6886
  ],
5862
6887
  loc,
5863
6888
  },
5864
- { kind: "return", value: ref("out.0", JSVAL), loc },
6889
+ { kind: "return", value: varRef("out.0", JSVAL, loc), loc },
5865
6890
  ],
5866
6891
  loc,
5867
6892
  });
@@ -5880,8 +6905,6 @@ export class Lowerer {
5880
6905
  this.jsinHelpers.set(key, name);
5881
6906
  const arrT = { kind: "array", elem };
5882
6907
  const f64 = { kind: "f64" };
5883
- const ref = (localId, type) => ({ kind: "varRef", localId, type, loc });
5884
- const num = (value) => ({ kind: "numLit", value, type: f64, loc });
5885
6908
  this.liftedFns.push({
5886
6909
  name,
5887
6910
  params: [{ localId: "a.0", name: "a", type: arrT }],
@@ -5897,17 +6920,17 @@ export class Lowerer {
5897
6920
  {
5898
6921
  kind: "varDecl",
5899
6922
  localId: "n.0",
5900
- init: { kind: "arrIntrinsic", method: "length", receiver: ref("a.0", arrT), args: [], type: f64, loc },
6923
+ init: { kind: "arrIntrinsic", method: "length", receiver: varRef("a.0", arrT, loc), args: [], type: f64, loc },
5901
6924
  loc,
5902
6925
  },
5903
6926
  {
5904
6927
  kind: "for",
5905
- init: { kind: "varDecl", localId: "i.0", init: num(0), loc },
5906
- cond: { kind: "bin", op: "<", left: ref("i.0", f64), right: ref("n.0", f64), type: BOOL, loc },
6928
+ init: { kind: "varDecl", localId: "i.0", init: numLit(0, loc), loc },
6929
+ cond: { kind: "bin", op: "<", left: varRef("i.0", f64, loc), right: varRef("n.0", f64, loc), type: BOOL, loc },
5907
6930
  update: {
5908
6931
  kind: "assign",
5909
6932
  localId: "i.0",
5910
- value: { kind: "bin", op: "+", left: ref("i.0", f64), right: num(1), type: f64, loc },
6933
+ value: { kind: "bin", op: "+", left: varRef("i.0", f64, loc), right: numLit(1, loc), type: f64, loc },
5911
6934
  loc,
5912
6935
  },
5913
6936
  body: [
@@ -5917,9 +6940,9 @@ export class Lowerer {
5917
6940
  kind: "jsOp",
5918
6941
  op: "setIdx",
5919
6942
  args: [
5920
- ref("out.0", JSVAL),
5921
- { kind: "jsMarshal", value: ref("i.0", f64), type: JSVAL, loc },
5922
- this.jsvalLiftExpr({ kind: "arrayGet", arr: ref("a.0", arrT), index: ref("i.0", f64), type: elem, loc }, loc),
6943
+ varRef("out.0", JSVAL, loc),
6944
+ { kind: "jsMarshal", value: varRef("i.0", f64, loc), type: JSVAL, loc },
6945
+ this.jsvalLiftExpr({ kind: "arrayGet", arr: varRef("a.0", arrT, loc), index: varRef("i.0", f64, loc), type: elem, loc }, loc),
5923
6946
  ],
5924
6947
  type: { kind: "void" },
5925
6948
  loc,
@@ -5929,7 +6952,7 @@ export class Lowerer {
5929
6952
  ],
5930
6953
  loc,
5931
6954
  },
5932
- { kind: "return", value: ref("out.0", JSVAL), loc },
6955
+ { kind: "return", value: varRef("out.0", JSVAL, loc), loc },
5933
6956
  ],
5934
6957
  loc,
5935
6958
  });
@@ -5951,8 +6974,6 @@ export class Lowerer {
5951
6974
  const arrT = { kind: "array", elem: fromElem };
5952
6975
  const outT = { kind: "array", elem: JSVAL };
5953
6976
  const f64 = { kind: "f64" };
5954
- const ref = (localId, type) => ({ kind: "varRef", localId, type, loc });
5955
- const num = (value) => ({ kind: "numLit", value, type: f64, loc });
5956
6977
  this.liftedFns.push({
5957
6978
  name,
5958
6979
  params: [{ localId: "a.0", name: "a", type: arrT }],
@@ -5968,17 +6989,17 @@ export class Lowerer {
5968
6989
  {
5969
6990
  kind: "varDecl",
5970
6991
  localId: "n.0",
5971
- init: { kind: "arrIntrinsic", method: "length", receiver: ref("a.0", arrT), args: [], type: f64, loc },
6992
+ init: { kind: "arrIntrinsic", method: "length", receiver: varRef("a.0", arrT, loc), args: [], type: f64, loc },
5972
6993
  loc,
5973
6994
  },
5974
6995
  {
5975
6996
  kind: "for",
5976
- init: { kind: "varDecl", localId: "i.0", init: num(0), loc },
5977
- cond: { kind: "bin", op: "<", left: ref("i.0", f64), right: ref("n.0", f64), type: BOOL, loc },
6997
+ init: { kind: "varDecl", localId: "i.0", init: numLit(0, loc), loc },
6998
+ cond: { kind: "bin", op: "<", left: varRef("i.0", f64, loc), right: varRef("n.0", f64, loc), type: BOOL, loc },
5978
6999
  update: {
5979
7000
  kind: "assign",
5980
7001
  localId: "i.0",
5981
- value: { kind: "bin", op: "+", left: ref("i.0", f64), right: num(1), type: f64, loc },
7002
+ value: { kind: "bin", op: "+", left: varRef("i.0", f64, loc), right: numLit(1, loc), type: f64, loc },
5982
7003
  loc,
5983
7004
  },
5984
7005
  body: [
@@ -5987,9 +7008,9 @@ export class Lowerer {
5987
7008
  expr: {
5988
7009
  kind: "arrIntrinsic",
5989
7010
  method: "push",
5990
- receiver: ref("out.0", outT),
7011
+ receiver: varRef("out.0", outT, loc),
5991
7012
  args: [
5992
- this.jsvalLiftExpr({ kind: "arrayGet", arr: ref("a.0", arrT), index: ref("i.0", f64), type: fromElem, loc }, loc),
7013
+ this.jsvalLiftExpr({ kind: "arrayGet", arr: varRef("a.0", arrT, loc), index: varRef("i.0", f64, loc), type: fromElem, loc }, loc),
5993
7014
  ],
5994
7015
  type: f64,
5995
7016
  loc,
@@ -5999,7 +7020,7 @@ export class Lowerer {
5999
7020
  ],
6000
7021
  loc,
6001
7022
  },
6002
- { kind: "return", value: ref("out.0", outT), loc },
7023
+ { kind: "return", value: varRef("out.0", outT, loc), loc },
6003
7024
  ],
6004
7025
  loc,
6005
7026
  });
@@ -6998,6 +8019,14 @@ export class Lowerer {
6998
8019
  }
6999
8020
  const local = this.declareLocal(decl.name, name, shape.type, true);
7000
8021
  params.push({ localId: local.id, name, type: local.type });
8022
+ if (shape.mode === "required" &&
8023
+ shape.type.kind === "union" &&
8024
+ this.armTag(shape.type.unionId, UNDEFINED_T) >= 0 &&
8025
+ typeEquals(this.stripUndefinedArm(shape.type), this.mapTypeOf(this.typeOf(decl.name)) ?? VOID)) {
8026
+ const root = this.runtimeOptionalRootOf(local);
8027
+ this.runtimeOptionalLocals.add(root);
8028
+ this.runtimeOptionalStorageLocals.add(root);
8029
+ }
7001
8030
  });
7002
8031
  return { params, prologue };
7003
8032
  }
@@ -7466,7 +8495,13 @@ export class Lowerer {
7466
8495
  return lowerExprStatement(this, expr);
7467
8496
  }
7468
8497
  lowerForOf(stmt) {
7469
- return lowerForOf(this, stmt);
8498
+ const optional = this.runtimeOptionalIdentifierValue(stmt.expression);
8499
+ if (optional?.present.kind !== "string")
8500
+ return lowerForOf(this, stmt);
8501
+ const helper = this.narrowedArmHelper(optional.unionId, optional.present, locOf(stmt.expression));
8502
+ if (!helper)
8503
+ return lowerForOf(this, stmt);
8504
+ return this.withExpressionOverride(stmt.expression, { kind: "call", callee: helper, args: [optional.value], type: optional.present, loc: locOf(stmt.expression) }, () => lowerForOf(this, stmt));
7470
8505
  }
7471
8506
  lowerForStatement(stmt) {
7472
8507
  return lowerForStatement(this, stmt);
@@ -7513,7 +8548,7 @@ export class Lowerer {
7513
8548
  * node_modules but NOT the standard library (typescript's own lib files
7514
8549
  * live under node_modules too), or inside a registered workspace-linked
7515
8550
  * package (a node_modules symlink whose realpath'd files carry no
7516
- * node_modules segment — shared.ts). The provenance half of the npm
8551
+ * node_modules segment — workspace-registry.ts). The provenance half of the npm
7517
8552
  * typing rule (package types are island handles) and of the per-package
7518
8553
  * requires-dynamic attribution. */
7519
8554
  isNpmFile = (sf) => sf.isDeclarationFile &&
@@ -7553,7 +8588,38 @@ export class Lowerer {
7553
8588
  return rejectThisInObjectMethod(this, node);
7554
8589
  }
7555
8590
  lowerElementAccess(expr) {
7556
- return lowerElementAccess(this, expr);
8591
+ const receiver = this.runtimeOptionalIdentifierValue(expr.expression);
8592
+ const receiverValue = receiver && (receiver.present.kind === "array" || receiver.present.kind === "record")
8593
+ ? (() => {
8594
+ const helper = this.narrowedArmHelper(receiver.unionId, receiver.present, locOf(expr.expression));
8595
+ return helper ? { kind: "call", callee: helper, args: [receiver.value], type: receiver.present, loc: locOf(expr.expression) } : null;
8596
+ })()
8597
+ : null;
8598
+ if (receiverValue && receiver?.present.kind === "record" && ts.isNumericLiteral(expr.argumentExpression)) {
8599
+ const shape = this.shapes.get(receiver.present.shapeId);
8600
+ const index = expr.argumentExpression.text;
8601
+ const field = shape?.tuple ? shape.fields.find((candidate) => candidate.name === String(Number(index))) : undefined;
8602
+ if (field) {
8603
+ const read = {
8604
+ kind: "recordGet",
8605
+ obj: receiverValue,
8606
+ shapeId: receiver.present.shapeId,
8607
+ field: field.name,
8608
+ type: field.type,
8609
+ loc: locOf(expr),
8610
+ };
8611
+ if (expr.parent && ts.isTypeOfExpression(expr.parent) &&
8612
+ (field.type.kind === "f64" || field.type.kind === "bool" || field.type.kind === "string")) {
8613
+ return { kind: "dynFrom", value: read, type: DYN, loc: locOf(expr) };
8614
+ }
8615
+ return read;
8616
+ }
8617
+ }
8618
+ const key = this.runtimeOptionalIdentifierValue(expr.argumentExpression);
8619
+ const keyValue = key?.present.kind === "string" ? this.ensureString(key.value, expr.argumentExpression) : null;
8620
+ const lower = () => lowerElementAccess(this, expr);
8621
+ const withKey = () => keyValue ? this.withExpressionOverride(expr.argumentExpression, keyValue, lower) : lower();
8622
+ return receiverValue ? this.withExpressionOverride(expr.expression, receiverValue, withKey) : withKey();
7557
8623
  }
7558
8624
  lowerRecordKeyRead(expr, shapeId, shape, includeUndefined = false) {
7559
8625
  return lowerRecordKeyRead(this, expr, shapeId, shape, includeUndefined);
@@ -7620,7 +8686,84 @@ export class Lowerer {
7620
8686
  return caughtToString(this, node);
7621
8687
  }
7622
8688
  lowerInstanceOf(expr, loc) {
7623
- return lowerInstanceOf(this, expr, loc);
8689
+ const lower = () => this.withRuntimeOptionalClassValue(expr.right, () => lowerInstanceOf(this, expr, loc));
8690
+ if (!ts.isIdentifier(expr.right) || this.mapTypeOf(this.typeOf(expr.right))?.kind !== "classval") {
8691
+ return lower();
8692
+ }
8693
+ const optionalLeft = this.runtimeOptionalIdentifierValue(expr.left);
8694
+ const left = optionalLeft?.value ?? (ts.isElementAccessExpression(expr.left) ? this.lowerExpr(expr.left) : null);
8695
+ if (!left)
8696
+ return lower();
8697
+ if (left.type.kind !== "union" || this.armTag(left.type.unionId, UNDEFINED_T) < 0)
8698
+ return lower();
8699
+ const present = this.stripUndefinedArm(left.type);
8700
+ if (present.kind !== "object")
8701
+ return lower();
8702
+ const undefinedTag = this.armTag(left.type.unionId, UNDEFINED_T);
8703
+ const valueTag = this.armTag(left.type.unionId, present);
8704
+ if (undefinedTag < 0 || valueTag < 0)
8705
+ return lower();
8706
+ const stable = this.declareHiddenLocal("%instanceofLeft", left.type);
8707
+ const value = varRef(stable.id, left.type, locOf(expr.left));
8708
+ const optionalRight = this.runtimeOptionalIdentifierValue(expr.right);
8709
+ let right;
8710
+ if (optionalRight?.present.kind === "classval") {
8711
+ const helper = this.narrowedArmHelper(optionalRight.unionId, optionalRight.present, locOf(expr.right));
8712
+ if (!helper)
8713
+ return lower();
8714
+ right = { kind: "call", callee: helper, args: [optionalRight.value], type: optionalRight.present, loc: locOf(expr.right) };
8715
+ }
8716
+ else {
8717
+ right = this.lowerExpr(expr.right);
8718
+ }
8719
+ if (right.type.kind !== "classval")
8720
+ return lower();
8721
+ const stableRight = this.declareHiddenLocal("%instanceofRight", right.type);
8722
+ const rightValue = varRef(stableRight.id, right.type, locOf(expr.right));
8723
+ const body = this.withExpressionOverride(expr.left, {
8724
+ kind: "unionNarrow", unionId: left.type.unionId, tag: valueTag, value, type: present, loc: locOf(expr.left),
8725
+ }, () => this.withExpressionOverride(expr.right, rightValue, () => lowerInstanceOf(this, expr, loc)));
8726
+ return {
8727
+ kind: "seqExpr",
8728
+ stmts: [
8729
+ { kind: "varDecl", localId: stable.id, init: left, loc: locOf(expr.left) },
8730
+ { kind: "varDecl", localId: stableRight.id, init: right, loc: locOf(expr.right) },
8731
+ ],
8732
+ result: {
8733
+ kind: "ternary",
8734
+ cond: { kind: "unionIsTag", unionId: left.type.unionId, tag: undefinedTag, negated: false, value, type: BOOL, loc },
8735
+ then: { kind: "boolLit", value: false, type: BOOL, loc },
8736
+ else_: body,
8737
+ type: BOOL,
8738
+ loc,
8739
+ },
8740
+ type: BOOL,
8741
+ loc,
8742
+ };
8743
+ }
8744
+ withRuntimeOptionalClassValue(node, lower) {
8745
+ if (this.mapTypeOf(this.typeOf(node))?.kind !== "classval")
8746
+ return lower();
8747
+ const optional = this.runtimeOptionalIdentifierValue(node);
8748
+ if (optional?.present.kind !== "classval")
8749
+ return lower();
8750
+ const helper = this.narrowedArmHelper(optional.unionId, optional.present, locOf(node));
8751
+ if (!helper)
8752
+ return lower();
8753
+ return this.withExpressionOverride(node, { kind: "call", callee: helper, args: [optional.value], type: optional.present, loc: locOf(node) }, lower);
8754
+ }
8755
+ withExpressionOverride(node, value, lower) {
8756
+ const previous = this.chainRecvByNode.get(node);
8757
+ this.chainRecvByNode.set(node, value);
8758
+ try {
8759
+ return lower();
8760
+ }
8761
+ finally {
8762
+ if (previous)
8763
+ this.chainRecvByNode.set(node, previous);
8764
+ else
8765
+ this.chainRecvByNode.delete(node);
8766
+ }
7624
8767
  }
7625
8768
  lowerCall(expr) {
7626
8769
  // Ambient fetch (native in static builds, island-backed under
@@ -7760,7 +8903,8 @@ export class Lowerer {
7760
8903
  const arg = this.lowerExpr(expr.arguments[0]);
7761
8904
  return { kind: "jsOp", op: "construct", args: [ctor, arg], type: JSVAL, loc };
7762
8905
  }
7763
- return lowerAbortControllerNew(this, expr) ?? lowerResponseNew(this, expr) ?? lowerStaticReadableStreamNew(this, expr) ?? lowerNew(this, expr);
8906
+ const builtin = lowerAbortControllerNew(this, expr) ?? lowerResponseNew(this, expr) ?? lowerStaticReadableStreamNew(this, expr);
8907
+ return builtin ?? this.withRuntimeOptionalClassValue(expr.expression, () => lowerNew(this, expr));
7764
8908
  }
7765
8909
  lowerFieldRead(expr) {
7766
8910
  // `C.x` static reads first (the receiver is a CLASS, not an instance
@@ -8249,6 +9393,13 @@ export class Lowerer {
8249
9393
  return lowerStringLastIndexOfCall(this, call, access);
8250
9394
  }
8251
9395
  lowerFilterNarrowCall(call, access) {
9396
+ // Native array filters use the state-aware HOF helper: its callback
9397
+ // receives present undefined values and skips holes before a narrowed
9398
+ // survivor is extracted. The older narrowing helper reads the payload
9399
+ // directly and therefore cannot represent that three-state contract.
9400
+ if (this.mapTypeOf(this.typeOf(access.expression))?.kind === "array" && this.isStdlibMember(access)) {
9401
+ return null;
9402
+ }
8252
9403
  return lowerFilterNarrowCall(this, call, access);
8253
9404
  }
8254
9405
  lowerPromiseMethodCall(call, access) {