@scriptc/compiler 0.1.7 → 0.2.0

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 (1032) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +73 -24
  2. package/ambient/scriptc-overrides.d.ts +10 -6
  3. package/ambient/scriptc.d.ts +15 -0
  4. package/dist/backend/build-cache.d.ts +1 -3
  5. package/dist/backend/build-cache.js +3 -22
  6. package/dist/backend/build-cache.js.map +1 -1
  7. package/dist/backend/cache-root.d.ts +3 -0
  8. package/dist/backend/cache-root.js +23 -0
  9. package/dist/backend/cache-root.js.map +1 -0
  10. package/dist/backend/cycle-analysis.d.ts +15 -0
  11. package/dist/backend/cycle-analysis.js +107 -0
  12. package/dist/backend/cycle-analysis.js.map +1 -0
  13. package/dist/backend/cycle-analysis.test.js +124 -0
  14. package/dist/backend/cycle-analysis.test.js.map +1 -0
  15. package/dist/backend/executable-features.d.ts +4 -0
  16. package/dist/backend/executable-features.js +42 -0
  17. package/dist/backend/executable-features.js.map +1 -0
  18. package/dist/backend/external-c.d.ts +5 -27
  19. package/dist/backend/external-c.js +5 -40
  20. package/dist/backend/external-c.js.map +1 -1
  21. package/dist/backend/ffi-callbacks.d.ts +2 -3
  22. package/dist/backend/ffi-callbacks.js +2 -3
  23. package/dist/backend/ffi-callbacks.js.map +1 -1
  24. package/dist/backend/library-identity-markers.d.ts +4 -9
  25. package/dist/backend/library-identity-markers.js +11 -49
  26. package/dist/backend/library-identity-markers.js.map +1 -1
  27. package/dist/backend/library-pack.d.ts +5 -0
  28. package/dist/backend/library-pack.js +123 -0
  29. package/dist/backend/library-pack.js.map +1 -0
  30. package/dist/backend/link-plan-core.d.ts +20 -0
  31. package/dist/backend/link-plan-core.js +18 -0
  32. package/dist/backend/link-plan-core.js.map +1 -0
  33. package/dist/backend/link-plan.d.ts +1 -1
  34. package/dist/backend/link-plan.js +16 -17
  35. package/dist/backend/link-plan.js.map +1 -1
  36. package/dist/backend/link-trace.d.ts +2 -0
  37. package/dist/backend/link-trace.js +24 -0
  38. package/dist/backend/link-trace.js.map +1 -0
  39. package/dist/backend/linker.js +1 -1
  40. package/dist/backend/linker.js.map +1 -1
  41. package/dist/backend/literals.d.ts +9 -0
  42. package/dist/backend/literals.js +35 -0
  43. package/dist/backend/literals.js.map +1 -0
  44. package/dist/backend/literals.test.d.ts +1 -0
  45. package/dist/backend/literals.test.js +53 -0
  46. package/dist/backend/literals.test.js.map +1 -0
  47. package/dist/backend/llvm/blocks.d.ts +2 -0
  48. package/dist/backend/llvm/blocks.js +9 -4
  49. package/dist/backend/llvm/blocks.js.map +1 -1
  50. package/dist/backend/llvm/blocks.test.d.ts +1 -0
  51. package/dist/backend/llvm/blocks.test.js +91 -0
  52. package/dist/backend/llvm/blocks.test.js.map +1 -0
  53. package/dist/backend/llvm/classes.d.ts +14 -8
  54. package/dist/backend/llvm/classes.js +70 -28
  55. package/dist/backend/llvm/classes.js.map +1 -1
  56. package/dist/backend/llvm/common.d.ts +5 -1
  57. package/dist/backend/llvm/common.js +45 -4
  58. package/dist/backend/llvm/common.js.map +1 -1
  59. package/dist/backend/llvm/debug-info.js +2 -7
  60. package/dist/backend/llvm/debug-info.js.map +1 -1
  61. package/dist/backend/llvm/debug-info.test.d.ts +1 -0
  62. package/dist/backend/llvm/debug-info.test.js +110 -0
  63. package/dist/backend/llvm/debug-info.test.js.map +1 -0
  64. package/dist/backend/llvm/dyn.d.ts +16 -2
  65. package/dist/backend/llvm/dyn.js +494 -165
  66. package/dist/backend/llvm/dyn.js.map +1 -1
  67. package/dist/backend/llvm/emitter.d.ts +596 -1
  68. package/dist/backend/llvm/emitter.js +695 -410
  69. package/dist/backend/llvm/emitter.js.map +1 -1
  70. package/dist/backend/llvm/emitter.test.d.ts +1 -0
  71. package/dist/backend/llvm/emitter.test.js +179 -0
  72. package/dist/backend/llvm/emitter.test.js.map +1 -0
  73. package/dist/backend/llvm/expr-async.js +23 -14
  74. package/dist/backend/llvm/expr-async.js.map +1 -1
  75. package/dist/backend/llvm/expr-bytes.d.ts +1 -1
  76. package/dist/backend/llvm/expr-bytes.js +32 -14
  77. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  78. package/dist/backend/llvm/expr-callbacks.d.ts +1 -1
  79. package/dist/backend/llvm/expr-callbacks.js +25 -22
  80. package/dist/backend/llvm/expr-callbacks.js.map +1 -1
  81. package/dist/backend/llvm/expr-calls.js +136 -35
  82. package/dist/backend/llvm/expr-calls.js.map +1 -1
  83. package/dist/backend/llvm/expr-containers.d.ts +1 -1
  84. package/dist/backend/llvm/expr-containers.js +43 -14
  85. package/dist/backend/llvm/expr-containers.js.map +1 -1
  86. package/dist/backend/llvm/expr-context.d.ts +5 -260
  87. package/dist/backend/llvm/expr-control.js +9 -5
  88. package/dist/backend/llvm/expr-control.js.map +1 -1
  89. package/dist/backend/llvm/expr-dispatch.d.ts +1 -1
  90. package/dist/backend/llvm/expr-dispatch.js +2 -0
  91. package/dist/backend/llvm/expr-dispatch.js.map +1 -1
  92. package/dist/backend/llvm/expr-dynamic.js +62 -74
  93. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  94. package/dist/backend/llvm/expr-island.d.ts +1 -1
  95. package/dist/backend/llvm/expr-island.js +11 -7
  96. package/dist/backend/llvm/expr-island.js.map +1 -1
  97. package/dist/backend/llvm/expr-primitives.d.ts +1 -1
  98. package/dist/backend/llvm/expr-primitives.js +51 -30
  99. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  100. package/dist/backend/llvm/expr-primitives.test.js +1 -1
  101. package/dist/backend/llvm/expr-records.d.ts +5 -1
  102. package/dist/backend/llvm/expr-records.js +43 -4
  103. package/dist/backend/llvm/expr-records.js.map +1 -1
  104. package/dist/backend/llvm/expr-stream-bridges.d.ts +4 -4
  105. package/dist/backend/llvm/expr-stream-bridges.js +102 -121
  106. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  107. package/dist/backend/llvm/expr-stream-bridges.test.d.ts +1 -0
  108. package/dist/backend/llvm/expr-stream-bridges.test.js +55 -0
  109. package/dist/backend/llvm/expr-stream-bridges.test.js.map +1 -0
  110. package/dist/backend/llvm/expr-stream-callbacks.d.ts +1 -1
  111. package/dist/backend/llvm/expr-stream-callbacks.js +12 -12
  112. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
  113. package/dist/backend/llvm/layouts.d.ts +19 -0
  114. package/dist/backend/llvm/layouts.js +12 -0
  115. package/dist/backend/llvm/layouts.js.map +1 -0
  116. package/dist/backend/llvm/lib-abi.d.ts +19 -0
  117. package/dist/backend/llvm/lib-abi.js +82 -0
  118. package/dist/backend/llvm/lib-abi.js.map +1 -0
  119. package/dist/backend/llvm/lib-connect.d.ts +2 -0
  120. package/dist/backend/llvm/lib-connect.js +51 -0
  121. package/dist/backend/llvm/lib-connect.js.map +1 -0
  122. package/dist/backend/llvm/lib-datagram.d.ts +2 -0
  123. package/dist/backend/llvm/lib-datagram.js +135 -0
  124. package/dist/backend/llvm/lib-datagram.js.map +1 -0
  125. package/dist/backend/llvm/lib-dispatch.js +50 -6
  126. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  127. package/dist/backend/llvm/lib-filesystem.js +30 -18
  128. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  129. package/dist/backend/llvm/lib-http2.d.ts +2 -0
  130. package/dist/backend/llvm/lib-http2.js +215 -0
  131. package/dist/backend/llvm/lib-http2.js.map +1 -0
  132. package/dist/backend/llvm/lib-lookup.d.ts +2 -0
  133. package/dist/backend/llvm/lib-lookup.js +39 -0
  134. package/dist/backend/llvm/lib-lookup.js.map +1 -0
  135. package/dist/backend/llvm/lib-network.js +25 -2
  136. package/dist/backend/llvm/lib-network.js.map +1 -1
  137. package/dist/backend/llvm/lib-process.js +21 -16
  138. package/dist/backend/llvm/lib-process.js.map +1 -1
  139. package/dist/backend/llvm/lib-shared.js +117 -1
  140. package/dist/backend/llvm/lib-shared.js.map +1 -1
  141. package/dist/backend/llvm/lib-stream.js +3 -2
  142. package/dist/backend/llvm/lib-stream.js.map +1 -1
  143. package/dist/backend/llvm/lib-test.d.ts +2 -0
  144. package/dist/backend/llvm/lib-test.js +34 -0
  145. package/dist/backend/llvm/lib-test.js.map +1 -0
  146. package/dist/backend/llvm/lib-tls.d.ts +2 -0
  147. package/dist/backend/llvm/lib-tls.js +82 -0
  148. package/dist/backend/llvm/lib-tls.js.map +1 -0
  149. package/dist/backend/llvm/shapes.d.ts +10 -9
  150. package/dist/backend/llvm/shapes.js +35 -130
  151. package/dist/backend/llvm/shapes.js.map +1 -1
  152. package/dist/backend/llvm/unsupported.d.ts +1 -0
  153. package/dist/backend/llvm/unsupported.js +1 -2
  154. package/dist/backend/llvm/unsupported.js.map +1 -1
  155. package/dist/backend/llvm/walkers.js +1 -7
  156. package/dist/backend/llvm/walkers.js.map +1 -1
  157. package/dist/backend/mangle.d.ts +2 -2
  158. package/dist/backend/mangle.js +16 -5
  159. package/dist/backend/mangle.js.map +1 -1
  160. package/dist/backend/{c/may-throw.d.ts → may-throw.d.ts} +1 -1
  161. package/dist/backend/{c/may-throw.js → may-throw.js} +51 -46
  162. package/dist/backend/may-throw.js.map +1 -0
  163. package/dist/backend/may-throw.test.d.ts +1 -0
  164. package/dist/backend/may-throw.test.js +58 -0
  165. package/dist/backend/may-throw.test.js.map +1 -0
  166. package/dist/backend/native-codegen-core.d.ts +22 -0
  167. package/dist/backend/native-codegen-core.js +44 -0
  168. package/dist/backend/native-codegen-core.js.map +1 -0
  169. package/dist/backend/native-codegen.d.ts +3 -19
  170. package/dist/backend/native-codegen.js +5 -44
  171. package/dist/backend/native-codegen.js.map +1 -1
  172. package/dist/backend/native-codegen.test.js +2 -2
  173. package/dist/backend/native-codegen.test.js.map +1 -1
  174. package/dist/backend/native-link-info-core.d.ts +94 -0
  175. package/dist/backend/native-link-info-core.js +62 -0
  176. package/dist/backend/native-link-info-core.js.map +1 -0
  177. package/dist/backend/native-link-info.d.ts +3 -88
  178. package/dist/backend/native-link-info.js +12 -243
  179. package/dist/backend/native-link-info.js.map +1 -1
  180. package/dist/backend/native-link-info.test.js +41 -146
  181. package/dist/backend/native-link-info.test.js.map +1 -1
  182. package/dist/backend/native-toolchain.d.ts +10 -25
  183. package/dist/backend/native-toolchain.js +31 -211
  184. package/dist/backend/native-toolchain.js.map +1 -1
  185. package/dist/backend/native-toolchain.test.js +5 -5
  186. package/dist/backend/native-toolchain.test.js.map +1 -1
  187. package/dist/backend/native-tools.d.ts +24 -0
  188. package/dist/backend/native-tools.js +33 -0
  189. package/dist/backend/native-tools.js.map +1 -0
  190. package/dist/backend/object-localize.js +19 -8
  191. package/dist/backend/object-localize.js.map +1 -1
  192. package/dist/backend/object-localize.test.js +22 -0
  193. package/dist/backend/object-localize.test.js.map +1 -1
  194. package/dist/backend/runtime-abi.d.ts +2 -2
  195. package/dist/backend/runtime-abi.js +2 -2
  196. package/dist/backend/runtime-pack-core.d.ts +101 -0
  197. package/dist/backend/runtime-pack-core.js +172 -0
  198. package/dist/backend/runtime-pack-core.js.map +1 -0
  199. package/dist/backend/runtime-pack-native.d.ts +21 -0
  200. package/dist/backend/runtime-pack-native.js +70 -0
  201. package/dist/backend/runtime-pack-native.js.map +1 -0
  202. package/dist/backend/runtime-pack-targets.test.js +1 -1
  203. package/dist/backend/runtime-pack.d.ts +3 -83
  204. package/dist/backend/runtime-pack.js +8 -151
  205. package/dist/backend/runtime-pack.js.map +1 -1
  206. package/dist/backend/runtime-pack.test.js +24 -1
  207. package/dist/backend/runtime-pack.test.js.map +1 -1
  208. package/dist/backend/target-diagnostics.d.ts +22 -0
  209. package/dist/backend/target-diagnostics.js +108 -0
  210. package/dist/backend/target-diagnostics.js.map +1 -0
  211. package/dist/backend/target-platform.d.ts +15 -0
  212. package/dist/backend/target-platform.js +72 -0
  213. package/dist/backend/target-platform.js.map +1 -0
  214. package/dist/backend/targets.d.ts +13 -4
  215. package/dist/backend/targets.js +95 -30
  216. package/dist/backend/targets.js.map +1 -1
  217. package/dist/backend/targets.test.js +65 -4
  218. package/dist/backend/targets.test.js.map +1 -1
  219. package/dist/backend/toolchain-environment.d.ts +6 -0
  220. package/dist/backend/toolchain-environment.js +99 -0
  221. package/dist/backend/toolchain-environment.js.map +1 -0
  222. package/dist/backend/vendor-archives.d.ts +1 -9
  223. package/dist/backend/vendor-archives.js +2 -9
  224. package/dist/backend/vendor-archives.js.map +1 -1
  225. package/dist/backend/vendor-inputs.d.ts +9 -0
  226. package/dist/backend/vendor-inputs.js +10 -0
  227. package/dist/backend/vendor-inputs.js.map +1 -0
  228. package/dist/backend/warm-cache.d.ts +3 -0
  229. package/dist/backend/warm-cache.js +41 -0
  230. package/dist/backend/warm-cache.js.map +1 -0
  231. package/dist/cli/command.d.ts +3 -0
  232. package/dist/cli/command.js +328 -0
  233. package/dist/cli/command.js.map +1 -0
  234. package/dist/cli/host.d.ts +24 -0
  235. package/dist/cli/host.js +2 -0
  236. package/dist/cli/host.js.map +1 -0
  237. package/dist/cli/output-options.d.ts +26 -0
  238. package/dist/cli/output-options.js +60 -0
  239. package/dist/cli/output-options.js.map +1 -0
  240. package/dist/cli/paths.d.ts +12 -0
  241. package/dist/cli/paths.js +42 -0
  242. package/dist/cli/paths.js.map +1 -0
  243. package/dist/cli/usage.d.ts +74 -0
  244. package/dist/cli/usage.js +86 -0
  245. package/dist/cli/usage.js.map +1 -0
  246. package/dist/cli/wasi-paths.d.ts +8 -0
  247. package/dist/cli/wasi-paths.js +41 -0
  248. package/dist/cli/wasi-paths.js.map +1 -0
  249. package/dist/cli/wasi-runner.d.ts +2 -0
  250. package/dist/cli/wasi-runner.js +28 -0
  251. package/dist/cli/wasi-runner.js.map +1 -0
  252. package/dist/compat/fetch-profile.js +3 -3
  253. package/dist/compat/fetch-profile.js.map +1 -1
  254. package/dist/compile-types.d.ts +162 -0
  255. package/dist/compile-types.js +2 -0
  256. package/dist/compile-types.js.map +1 -0
  257. package/dist/coverage/report.js +11 -5
  258. package/dist/coverage/report.js.map +1 -1
  259. package/dist/coverage/surface-manifest.js +5 -2
  260. package/dist/coverage/surface-manifest.js.map +1 -1
  261. package/dist/diagnostics/diagnostic.js +3 -3
  262. package/dist/diagnostics/diagnostic.js.map +1 -1
  263. package/dist/executable/executable-cache.d.ts +3 -4
  264. package/dist/executable/executable-cache.js +5 -6
  265. package/dist/executable/executable-cache.js.map +1 -1
  266. package/dist/executable/executable-cache.test.js +16 -17
  267. package/dist/executable/executable-cache.test.js.map +1 -1
  268. package/dist/executable/prepare.d.ts +14 -0
  269. package/dist/executable/prepare.js +66 -0
  270. package/dist/executable/prepare.js.map +1 -0
  271. package/dist/ffi/ffi-manifest.d.ts +11 -4
  272. package/dist/ffi/ffi-manifest.js +170 -58
  273. package/dist/ffi/ffi-manifest.js.map +1 -1
  274. package/dist/ffi/ffi-manifest.test.d.ts +1 -0
  275. package/dist/ffi/ffi-manifest.test.js +111 -0
  276. package/dist/ffi/ffi-manifest.test.js.map +1 -0
  277. package/dist/format-integer.d.ts +3 -0
  278. package/dist/format-integer.js +14 -0
  279. package/dist/format-integer.js.map +1 -0
  280. package/dist/frontend/analysis.d.ts +5 -0
  281. package/dist/frontend/analysis.js +88 -0
  282. package/dist/frontend/analysis.js.map +1 -0
  283. package/dist/frontend/arguments-usage.d.ts +1 -3
  284. package/dist/frontend/arguments-usage.js.map +1 -1
  285. package/dist/frontend/builtin-modules.d.ts +1 -1
  286. package/dist/frontend/builtin-modules.js +1 -1
  287. package/dist/frontend/builtin-modules.js.map +1 -1
  288. package/dist/frontend/cjs-lexer.d.ts +4 -25
  289. package/dist/frontend/cjs-lexer.js +6 -806
  290. package/dist/frontend/cjs-lexer.js.map +1 -1
  291. package/dist/frontend/cjs-resolve.d.ts +5 -0
  292. package/dist/frontend/cjs-resolve.js +429 -0
  293. package/dist/frontend/cjs-resolve.js.map +1 -0
  294. package/dist/frontend/cjs-syntax.d.ts +26 -0
  295. package/dist/frontend/cjs-syntax.js +806 -0
  296. package/dist/frontend/cjs-syntax.js.map +1 -0
  297. package/dist/frontend/comptime-node.d.ts +4 -0
  298. package/dist/frontend/comptime-node.js +16 -0
  299. package/dist/frontend/comptime-node.js.map +1 -0
  300. package/dist/frontend/comptime-node.test.d.ts +1 -0
  301. package/dist/frontend/comptime-node.test.js +37 -0
  302. package/dist/frontend/comptime-node.test.js.map +1 -0
  303. package/dist/frontend/dts-paths.d.ts +3 -4
  304. package/dist/frontend/dts-paths.js +15 -8
  305. package/dist/frontend/dts-paths.js.map +1 -1
  306. package/dist/frontend/fork-target.js +2 -2
  307. package/dist/frontend/fork-target.js.map +1 -1
  308. package/dist/frontend/helper-tokens.d.ts +1 -0
  309. package/dist/frontend/helper-tokens.js +147 -0
  310. package/dist/frontend/helper-tokens.js.map +1 -0
  311. package/dist/frontend/helper-tokens.test.d.ts +1 -0
  312. package/dist/frontend/helper-tokens.test.js +35 -0
  313. package/dist/frontend/helper-tokens.test.js.map +1 -0
  314. package/dist/frontend/inferred-js-diagnostics.d.ts +5 -0
  315. package/dist/frontend/inferred-js-diagnostics.js +69 -0
  316. package/dist/frontend/inferred-js-diagnostics.js.map +1 -0
  317. package/dist/frontend/inferred-js-diagnostics.test.d.ts +1 -0
  318. package/dist/frontend/inferred-js-diagnostics.test.js +58 -0
  319. package/dist/frontend/inferred-js-diagnostics.test.js.map +1 -0
  320. package/dist/frontend/input-tracker.d.ts +5 -2
  321. package/dist/frontend/input-tracker.js +24 -3
  322. package/dist/frontend/input-tracker.js.map +1 -1
  323. package/dist/frontend/input-tracker.test.js +23 -0
  324. package/dist/frontend/input-tracker.test.js.map +1 -1
  325. package/dist/frontend/lib-contract.js +32 -24
  326. package/dist/frontend/lib-contract.js.map +1 -1
  327. package/dist/frontend/literal-values.d.ts +4 -0
  328. package/dist/frontend/literal-values.js +21 -0
  329. package/dist/frontend/literal-values.js.map +1 -0
  330. package/dist/frontend/literal-values.test.d.ts +1 -0
  331. package/dist/frontend/literal-values.test.js +91 -0
  332. package/dist/frontend/literal-values.test.js.map +1 -0
  333. package/dist/frontend/lowering/abstract-equality.d.ts +1 -1
  334. package/dist/frontend/lowering/abstract-equality.js +3 -0
  335. package/dist/frontend/lowering/abstract-equality.js.map +1 -1
  336. package/dist/frontend/lowering/array-indexed-mutation.js +11 -6
  337. package/dist/frontend/lowering/array-indexed-mutation.js.map +1 -1
  338. package/dist/frontend/lowering/array-values.d.ts +4 -1
  339. package/dist/frontend/lowering/array-values.js +43 -1
  340. package/dist/frontend/lowering/array-values.js.map +1 -1
  341. package/dist/frontend/lowering/callback-arg.js +1 -0
  342. package/dist/frontend/lowering/callback-arg.js.map +1 -1
  343. package/dist/frontend/lowering/class-callbacks.d.ts +12 -0
  344. package/dist/frontend/lowering/class-callbacks.js +63 -0
  345. package/dist/frontend/lowering/class-callbacks.js.map +1 -0
  346. package/dist/frontend/lowering/class-descriptors.d.ts +9 -0
  347. package/dist/frontend/lowering/class-descriptors.js +73 -0
  348. package/dist/frontend/lowering/class-descriptors.js.map +1 -0
  349. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +41 -0
  350. package/dist/frontend/lowering/class-dynamic-dispatch.js +803 -0
  351. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -0
  352. package/dist/frontend/lowering/class-dynamic-dispatch.test.d.ts +1 -0
  353. package/dist/frontend/lowering/class-dynamic-dispatch.test.js +92 -0
  354. package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -0
  355. package/dist/frontend/lowering/class-instance-constructor.d.ts +7 -0
  356. package/dist/frontend/lowering/class-instance-constructor.js +64 -0
  357. package/dist/frontend/lowering/class-instance-constructor.js.map +1 -0
  358. package/dist/frontend/lowering/class-method-values.d.ts +10 -0
  359. package/dist/frontend/lowering/class-method-values.js +170 -0
  360. package/dist/frontend/lowering/class-method-values.js.map +1 -0
  361. package/dist/frontend/lowering/class-prototypes.d.ts +16 -0
  362. package/dist/frontend/lowering/class-prototypes.js +134 -0
  363. package/dist/frontend/lowering/class-prototypes.js.map +1 -0
  364. package/dist/frontend/lowering/class-static-data.d.ts +6 -0
  365. package/dist/frontend/lowering/class-static-data.js +56 -0
  366. package/dist/frontend/lowering/class-static-data.js.map +1 -0
  367. package/dist/frontend/lowering/containers/buffer-numeric-methods.d.ts +4 -0
  368. package/dist/frontend/lowering/containers/buffer-numeric-methods.js +26 -0
  369. package/dist/frontend/lowering/containers/buffer-numeric-methods.js.map +1 -0
  370. package/dist/frontend/lowering/containers/bytes.d.ts +11 -7
  371. package/dist/frontend/lowering/containers/bytes.js +164 -155
  372. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  373. package/dist/frontend/lowering/containers/string-and-regexp.d.ts +2 -2
  374. package/dist/frontend/lowering/containers/string-and-regexp.js +39 -16
  375. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  376. package/dist/frontend/lowering/containers/string-replacement.d.ts +7 -0
  377. package/dist/frontend/lowering/containers/string-replacement.js +217 -0
  378. package/dist/frontend/lowering/containers/string-replacement.js.map +1 -0
  379. package/dist/frontend/lowering/error-methods.d.ts +11 -0
  380. package/dist/frontend/lowering/error-methods.js +78 -0
  381. package/dist/frontend/lowering/error-methods.js.map +1 -0
  382. package/dist/frontend/lowering/expressions/global-symbols.d.ts +6 -0
  383. package/dist/frontend/lowering/expressions/global-symbols.js +11 -0
  384. package/dist/frontend/lowering/expressions/global-symbols.js.map +1 -0
  385. package/dist/frontend/lowering/expressions/native-proxy.d.ts +7 -0
  386. package/dist/frontend/lowering/expressions/native-proxy.js +49 -0
  387. package/dist/frontend/lowering/expressions/native-proxy.js.map +1 -0
  388. package/dist/frontend/lowering/expressions/nullish-assignment.d.ts +6 -0
  389. package/dist/frontend/lowering/expressions/nullish-assignment.js +124 -0
  390. package/dist/frontend/lowering/expressions/nullish-assignment.js.map +1 -0
  391. package/dist/frontend/lowering/expressions/object-literals.d.ts +8 -8
  392. package/dist/frontend/lowering/expressions/object-literals.js +473 -178
  393. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  394. package/dist/frontend/lowering/expressions/optional-chains.js +20 -8
  395. package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
  396. package/dist/frontend/lowering/expressions/try-lower-expression.js +1 -0
  397. package/dist/frontend/lowering/expressions/try-lower-expression.js.map +1 -1
  398. package/dist/frontend/lowering/expressions/union-field-write.d.ts +8 -0
  399. package/dist/frontend/lowering/expressions/union-field-write.js +71 -0
  400. package/dist/frontend/lowering/expressions/union-field-write.js.map +1 -0
  401. package/dist/frontend/lowering/function-context.d.ts +93 -0
  402. package/dist/frontend/lowering/function-context.js +103 -0
  403. package/dist/frontend/lowering/function-context.js.map +1 -0
  404. package/dist/frontend/lowering/generator-delegation.d.ts +7 -0
  405. package/dist/frontend/lowering/generator-delegation.js +85 -0
  406. package/dist/frontend/lowering/generator-delegation.js.map +1 -0
  407. package/dist/frontend/lowering/generator-dynamic-dispatch.d.ts +10 -0
  408. package/dist/frontend/lowering/generator-dynamic-dispatch.js +105 -0
  409. package/dist/frontend/lowering/generator-dynamic-dispatch.js.map +1 -0
  410. package/dist/frontend/lowering/lib-boundary.d.ts +2 -1
  411. package/dist/frontend/lowering/lib-boundary.js +59 -20
  412. package/dist/frontend/lowering/lib-boundary.js.map +1 -1
  413. package/dist/frontend/lowering/lib-boundary.test.d.ts +1 -0
  414. package/dist/frontend/lowering/lib-boundary.test.js +45 -0
  415. package/dist/frontend/lowering/lib-boundary.test.js.map +1 -0
  416. package/dist/frontend/lowering/lower-array-sort.d.ts +1 -1
  417. package/dist/frontend/lowering/lower-assert.d.ts +1 -1
  418. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  419. package/dist/frontend/lowering/lower-async-iteration.d.ts +1 -1
  420. package/dist/frontend/lowering/lower-async-iteration.js.map +1 -1
  421. package/dist/frontend/lowering/lower-builtin-values.d.ts +12 -0
  422. package/dist/frontend/lowering/lower-builtin-values.js +139 -0
  423. package/dist/frontend/lowering/lower-builtin-values.js.map +1 -0
  424. package/dist/frontend/lowering/lower-builtins.d.ts +27 -41
  425. package/dist/frontend/lowering/lower-builtins.js +539 -343
  426. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  427. package/dist/frontend/lowering/lower-calls.d.ts +20 -17
  428. package/dist/frontend/lowering/lower-calls.js +1236 -353
  429. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  430. package/dist/frontend/lowering/lower-classes.d.ts +83 -45
  431. package/dist/frontend/lowering/lower-classes.js +952 -339
  432. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  433. package/dist/frontend/lowering/lower-comptime.d.ts +1 -1
  434. package/dist/frontend/lowering/lower-comptime.js +23 -32
  435. package/dist/frontend/lowering/lower-comptime.js.map +1 -1
  436. package/dist/frontend/lowering/lower-containers.d.ts +27 -32
  437. package/dist/frontend/lowering/lower-containers.js +796 -151
  438. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  439. package/dist/frontend/lowering/lower-dgram.d.ts +1 -1
  440. package/dist/frontend/lowering/lower-dgram.js.map +1 -1
  441. package/dist/frontend/lowering/lower-enums.d.ts +1 -1
  442. package/dist/frontend/lowering/lower-enums.js.map +1 -1
  443. package/dist/frontend/lowering/lower-event-emitter.d.ts +30 -1
  444. package/dist/frontend/lowering/lower-event-emitter.js +58 -26
  445. package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
  446. package/dist/frontend/lowering/lower-expando.d.ts +7 -1
  447. package/dist/frontend/lowering/lower-expando.js +14 -6
  448. package/dist/frontend/lowering/lower-expando.js.map +1 -1
  449. package/dist/frontend/lowering/lower-exprs.d.ts +35 -11
  450. package/dist/frontend/lowering/lower-exprs.js +1674 -779
  451. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  452. package/dist/frontend/lowering/lower-generators.d.ts +2 -5
  453. package/dist/frontend/lowering/lower-generators.js +77 -46
  454. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  455. package/dist/frontend/lowering/lower-global-value.d.ts +7 -0
  456. package/dist/frontend/lowering/lower-global-value.js +17 -0
  457. package/dist/frontend/lowering/lower-global-value.js.map +1 -0
  458. package/dist/frontend/lowering/lower-inspect.d.ts +1 -1
  459. package/dist/frontend/lowering/lower-inspect.js +17 -8
  460. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  461. package/dist/frontend/lowering/lower-island.d.ts +5 -8
  462. package/dist/frontend/lowering/lower-island.js +34 -23
  463. package/dist/frontend/lowering/lower-island.js.map +1 -1
  464. package/dist/frontend/lowering/lower-mixins.d.ts +2 -2
  465. package/dist/frontend/lowering/lower-mixins.js +5 -3
  466. package/dist/frontend/lowering/lower-mixins.js.map +1 -1
  467. package/dist/frontend/lowering/lower-modules.d.ts +1 -1
  468. package/dist/frontend/lowering/lower-modules.js +233 -30
  469. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  470. package/dist/frontend/lowering/lower-namespaces.d.ts +1 -1
  471. package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
  472. package/dist/frontend/lowering/lower-node-module.d.ts +1 -1
  473. package/dist/frontend/lowering/lower-node-module.js +13 -10
  474. package/dist/frontend/lowering/lower-node-module.js.map +1 -1
  475. package/dist/frontend/lowering/lower-server.d.ts +1 -1
  476. package/dist/frontend/lowering/lower-server.js +6 -10
  477. package/dist/frontend/lowering/lower-server.js.map +1 -1
  478. package/dist/frontend/lowering/lower-stmts.d.ts +10 -14
  479. package/dist/frontend/lowering/lower-stmts.js +728 -496
  480. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  481. package/dist/frontend/lowering/lower-stream.d.ts +1 -1
  482. package/dist/frontend/lowering/lower-stream.js +19 -10
  483. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  484. package/dist/frontend/lowering/lower-test.d.ts +1 -1
  485. package/dist/frontend/lowering/lower-test.js.map +1 -1
  486. package/dist/frontend/lowering/lower-url.d.ts +6 -0
  487. package/dist/frontend/lowering/lower-url.js +77 -0
  488. package/dist/frontend/lowering/lower-url.js.map +1 -0
  489. package/dist/frontend/lowering/lowerer.d.ts +113 -189
  490. package/dist/frontend/lowering/lowerer.js +1031 -672
  491. package/dist/frontend/lowering/lowerer.js.map +1 -1
  492. package/dist/frontend/lowering/lowerer.test.d.ts +1 -0
  493. package/dist/frontend/lowering/lowerer.test.js +26 -0
  494. package/dist/frontend/lowering/lowerer.test.js.map +1 -0
  495. package/dist/frontend/lowering/native-ffi.d.ts +5 -0
  496. package/dist/frontend/lowering/native-ffi.js +40 -0
  497. package/dist/frontend/lowering/native-ffi.js.map +1 -0
  498. package/dist/frontend/lowering/object-enumeration-receiver.d.ts +7 -0
  499. package/dist/frontend/lowering/object-enumeration-receiver.js +33 -0
  500. package/dist/frontend/lowering/object-enumeration-receiver.js.map +1 -0
  501. package/dist/frontend/lowering/object-factory-new.d.ts +8 -0
  502. package/dist/frontend/lowering/object-factory-new.js +68 -0
  503. package/dist/frontend/lowering/object-factory-new.js.map +1 -0
  504. package/dist/frontend/lowering/optional-arguments.js +6 -1
  505. package/dist/frontend/lowering/optional-arguments.js.map +1 -1
  506. package/dist/frontend/lowering/pairs-snapshot.js +2 -1
  507. package/dist/frontend/lowering/pairs-snapshot.js.map +1 -1
  508. package/dist/frontend/lowering/runtime-optional-locals.d.ts +14 -0
  509. package/dist/frontend/lowering/runtime-optional-locals.js +41 -0
  510. package/dist/frontend/lowering/runtime-optional-locals.js.map +1 -0
  511. package/dist/frontend/lowering/runtime-optional-locals.test.d.ts +1 -0
  512. package/dist/frontend/lowering/runtime-optional-locals.test.js +85 -0
  513. package/dist/frontend/lowering/runtime-optional-locals.test.js.map +1 -0
  514. package/dist/frontend/lowering/sanitize-class-types.d.ts +8 -0
  515. package/dist/frontend/lowering/sanitize-class-types.js +79 -0
  516. package/dist/frontend/lowering/sanitize-class-types.js.map +1 -0
  517. package/dist/frontend/lowering/sanitize-class-types.test.d.ts +1 -0
  518. package/dist/frontend/lowering/sanitize-class-types.test.js +60 -0
  519. package/dist/frontend/lowering/sanitize-class-types.test.js.map +1 -0
  520. package/dist/frontend/lowering/static-this.d.ts +5 -1
  521. package/dist/frontend/lowering/static-this.js +28 -2
  522. package/dist/frontend/lowering/static-this.js.map +1 -1
  523. package/dist/frontend/lowering/string-index.d.ts +7 -0
  524. package/dist/frontend/lowering/string-index.js +39 -0
  525. package/dist/frontend/lowering/string-index.js.map +1 -0
  526. package/dist/frontend/lowering/surfaces.d.ts +8 -3
  527. package/dist/frontend/lowering/surfaces.js +61 -29
  528. package/dist/frontend/lowering/surfaces.js.map +1 -1
  529. package/dist/frontend/lowering/symbol-fields.d.ts +22 -0
  530. package/dist/frontend/lowering/symbol-fields.js +183 -0
  531. package/dist/frontend/lowering/symbol-fields.js.map +1 -0
  532. package/dist/frontend/lowering/symbol-methods.d.ts +7 -0
  533. package/dist/frontend/lowering/symbol-methods.js +30 -0
  534. package/dist/frontend/lowering/symbol-methods.js.map +1 -0
  535. package/dist/frontend/lowering/text-decoder-encoding.d.ts +10 -0
  536. package/dist/frontend/lowering/text-decoder-encoding.js +77 -0
  537. package/dist/frontend/lowering/text-decoder-encoding.js.map +1 -0
  538. package/dist/frontend/lowering/text-decoder-encoding.test.d.ts +1 -0
  539. package/dist/frontend/lowering/text-decoder-encoding.test.js +38 -0
  540. package/dist/frontend/lowering/text-decoder-encoding.test.js.map +1 -0
  541. package/dist/frontend/lowering/union-narrow.d.ts +9 -0
  542. package/dist/frontend/lowering/union-narrow.js +59 -0
  543. package/dist/frontend/lowering/union-narrow.js.map +1 -0
  544. package/dist/frontend/lowering/union-narrow.test.d.ts +1 -0
  545. package/dist/frontend/lowering/union-narrow.test.js +72 -0
  546. package/dist/frontend/lowering/union-narrow.test.js.map +1 -0
  547. package/dist/frontend/lowering/union-retag.d.ts +43 -0
  548. package/dist/frontend/lowering/union-retag.js +259 -0
  549. package/dist/frontend/lowering/union-retag.js.map +1 -0
  550. package/dist/frontend/lowering/union-retag.test.d.ts +1 -0
  551. package/dist/frontend/lowering/union-retag.test.js +405 -0
  552. package/dist/frontend/lowering/union-retag.test.js.map +1 -0
  553. package/dist/frontend/lowering/unregistered-class-types.d.ts +14 -0
  554. package/dist/frontend/lowering/unregistered-class-types.js +94 -0
  555. package/dist/frontend/lowering/unregistered-class-types.js.map +1 -0
  556. package/dist/frontend/lowering/unregistered-class-types.test.d.ts +1 -0
  557. package/dist/frontend/lowering/unregistered-class-types.test.js +65 -0
  558. package/dist/frontend/lowering/unregistered-class-types.test.js.map +1 -0
  559. package/dist/frontend/lowering/width-lift.d.ts +40 -0
  560. package/dist/frontend/lowering/width-lift.js +2 -0
  561. package/dist/frontend/lowering/width-lift.js.map +1 -0
  562. package/dist/frontend/module-syntax.d.ts +58 -0
  563. package/dist/frontend/module-syntax.js +123 -0
  564. package/dist/frontend/module-syntax.js.map +1 -0
  565. package/dist/frontend/module-syntax.test.d.ts +1 -0
  566. package/dist/frontend/module-syntax.test.js +78 -0
  567. package/dist/frontend/module-syntax.test.js.map +1 -0
  568. package/dist/frontend/npm-fetch-analysis.d.ts +17 -0
  569. package/dist/frontend/npm-fetch-analysis.js +100 -0
  570. package/dist/frontend/npm-fetch-analysis.js.map +1 -0
  571. package/dist/frontend/npm-fetch-analysis.test.d.ts +1 -0
  572. package/dist/frontend/npm-fetch-analysis.test.js +107 -0
  573. package/dist/frontend/npm-fetch-analysis.test.js.map +1 -0
  574. package/dist/frontend/npm-fetch-node.d.ts +2 -0
  575. package/dist/frontend/npm-fetch-node.js +12 -0
  576. package/dist/frontend/npm-fetch-node.js.map +1 -0
  577. package/dist/frontend/npm-fetch-syntax.d.ts +6 -0
  578. package/dist/frontend/npm-fetch-syntax.js +207 -0
  579. package/dist/frontend/npm-fetch-syntax.js.map +1 -0
  580. package/dist/frontend/npm-node.d.ts +10 -0
  581. package/dist/frontend/npm-node.js +14 -0
  582. package/dist/frontend/npm-node.js.map +1 -0
  583. package/dist/frontend/npm-static-bundled-cjs.d.ts +8 -0
  584. package/dist/frontend/npm-static-bundled-cjs.js +236 -0
  585. package/dist/frontend/npm-static-bundled-cjs.js.map +1 -0
  586. package/dist/frontend/npm-static-bundled-cjs.test.d.ts +1 -0
  587. package/dist/frontend/npm-static-bundled-cjs.test.js +69 -0
  588. package/dist/frontend/npm-static-bundled-cjs.test.js.map +1 -0
  589. package/dist/frontend/npm-static-declaration-syntax.d.ts +57 -0
  590. package/dist/frontend/npm-static-declaration-syntax.js +944 -0
  591. package/dist/frontend/npm-static-declaration-syntax.js.map +1 -0
  592. package/dist/frontend/npm-static-declarations.d.ts +11 -39
  593. package/dist/frontend/npm-static-declarations.js +22 -561
  594. package/dist/frontend/npm-static-declarations.js.map +1 -1
  595. package/dist/frontend/npm-static-declarations.test.js +245 -6
  596. package/dist/frontend/npm-static-declarations.test.js.map +1 -1
  597. package/dist/frontend/npm-static-prune.d.ts +1 -1
  598. package/dist/frontend/npm-static-prune.js +5 -4
  599. package/dist/frontend/npm-static-prune.js.map +1 -1
  600. package/dist/frontend/npm-static-prune.test.js +1 -1
  601. package/dist/frontend/npm-static-prune.test.js.map +1 -1
  602. package/dist/frontend/npm-static-rewrite-host.d.ts +4 -0
  603. package/dist/frontend/npm-static-rewrite-host.js +179 -0
  604. package/dist/frontend/npm-static-rewrite-host.js.map +1 -0
  605. package/dist/frontend/npm-static-rewrite-syntax.d.ts +16 -0
  606. package/dist/frontend/npm-static-rewrite-syntax.js +905 -0
  607. package/dist/frontend/npm-static-rewrite-syntax.js.map +1 -0
  608. package/dist/frontend/npm-static-rewrite.d.ts +0 -5
  609. package/dist/frontend/npm-static-rewrite.js +2 -1079
  610. package/dist/frontend/npm-static-rewrite.js.map +1 -1
  611. package/dist/frontend/npm-static-subtyping.d.ts +5 -0
  612. package/dist/frontend/npm-static-subtyping.js +55 -0
  613. package/dist/frontend/npm-static-subtyping.js.map +1 -0
  614. package/dist/frontend/npm-static-subtyping.test.d.ts +1 -0
  615. package/dist/frontend/npm-static-subtyping.test.js +58 -0
  616. package/dist/frontend/npm-static-subtyping.test.js.map +1 -0
  617. package/dist/frontend/npm-static.d.ts +7 -15
  618. package/dist/frontend/npm-static.js +19 -28
  619. package/dist/frontend/npm-static.js.map +1 -1
  620. package/dist/frontend/npm.d.ts +8 -69
  621. package/dist/frontend/npm.js +21 -361
  622. package/dist/frontend/npm.js.map +1 -1
  623. package/dist/frontend/npm.test.js +2 -2
  624. package/dist/frontend/npm.test.js.map +1 -1
  625. package/dist/frontend/pipeline-native.d.ts +6 -0
  626. package/dist/frontend/pipeline-native.js +32 -0
  627. package/dist/frontend/pipeline-native.js.map +1 -0
  628. package/dist/frontend/pipeline.d.ts +54 -0
  629. package/dist/frontend/pipeline.js +382 -0
  630. package/dist/frontend/pipeline.js.map +1 -0
  631. package/dist/frontend/pipeline.test.d.ts +1 -0
  632. package/dist/frontend/pipeline.test.js +77 -0
  633. package/dist/frontend/pipeline.test.js.map +1 -0
  634. package/dist/frontend/program-analysis.d.ts +10 -0
  635. package/dist/frontend/program-analysis.js +14 -0
  636. package/dist/frontend/program-analysis.js.map +1 -0
  637. package/dist/frontend/program-node.d.ts +9 -0
  638. package/dist/frontend/program-node.js +48 -0
  639. package/dist/frontend/program-node.js.map +1 -0
  640. package/dist/frontend/program.d.ts +38 -19
  641. package/dist/frontend/program.js +344 -169
  642. package/dist/frontend/program.js.map +1 -1
  643. package/dist/frontend/program.test.js +87 -2
  644. package/dist/frontend/program.test.js.map +1 -1
  645. package/dist/frontend/provenance-core.d.ts +9 -0
  646. package/dist/frontend/provenance-core.js +435 -0
  647. package/dist/frontend/provenance-core.js.map +1 -0
  648. package/dist/frontend/provenance.d.ts +0 -4
  649. package/dist/frontend/provenance.js +4 -459
  650. package/dist/frontend/provenance.js.map +1 -1
  651. package/dist/frontend/resolve.d.ts +3 -1
  652. package/dist/frontend/resolve.js +6 -3
  653. package/dist/frontend/resolve.js.map +1 -1
  654. package/dist/frontend/runtime-resolve.d.ts +4 -3
  655. package/dist/frontend/runtime-resolve.js +22 -18
  656. package/dist/frontend/runtime-resolve.js.map +1 -1
  657. package/dist/frontend/runtime-resolve.test.js +53 -0
  658. package/dist/frontend/runtime-resolve.test.js.map +1 -1
  659. package/dist/frontend/services-node.d.ts +5 -0
  660. package/dist/frontend/services-node.js +19 -0
  661. package/dist/frontend/services-node.js.map +1 -0
  662. package/dist/frontend/services-node.test.d.ts +1 -0
  663. package/dist/frontend/services-node.test.js +70 -0
  664. package/dist/frontend/services-node.test.js.map +1 -0
  665. package/dist/frontend/services.d.ts +44 -0
  666. package/dist/frontend/services.js +90 -0
  667. package/dist/frontend/services.js.map +1 -0
  668. package/dist/frontend/services.test.d.ts +1 -0
  669. package/dist/frontend/services.test.js +174 -0
  670. package/dist/frontend/services.test.js.map +1 -0
  671. package/dist/frontend/ts7/adapter.d.ts +3 -3
  672. package/dist/frontend/ts7/adapter.js +14 -31
  673. package/dist/frontend/ts7/adapter.js.map +1 -1
  674. package/dist/frontend/ts7/api.d.ts +16 -0
  675. package/dist/frontend/ts7/api.js +24 -0
  676. package/dist/frontend/ts7/api.js.map +1 -0
  677. package/dist/frontend/ts7/ast-bytes.d.ts +31 -0
  678. package/dist/frontend/ts7/ast-bytes.js +137 -0
  679. package/dist/frontend/ts7/ast-bytes.js.map +1 -0
  680. package/dist/frontend/ts7/ast-bytes.test.d.ts +1 -0
  681. package/dist/frontend/ts7/ast-bytes.test.js +73 -0
  682. package/dist/frontend/ts7/ast-bytes.test.js.map +1 -0
  683. package/dist/frontend/ts7/ast-guards.generated.d.ts +353 -0
  684. package/dist/frontend/ts7/ast-guards.generated.js +1951 -0
  685. package/dist/frontend/ts7/ast-guards.generated.js.map +1 -0
  686. package/dist/frontend/ts7/ast-guards.test.d.ts +1 -0
  687. package/dist/frontend/ts7/ast-guards.test.js +43 -0
  688. package/dist/frontend/ts7/ast-guards.test.js.map +1 -0
  689. package/dist/frontend/ts7/ast-node.d.ts +194 -0
  690. package/dist/frontend/ts7/ast-node.js +448 -0
  691. package/dist/frontend/ts7/ast-node.js.map +1 -0
  692. package/dist/frontend/ts7/ast-node.test.d.ts +1 -0
  693. package/dist/frontend/ts7/ast-node.test.js +266 -0
  694. package/dist/frontend/ts7/ast-node.test.js.map +1 -0
  695. package/dist/frontend/ts7/ast-schema.generated.d.ts +503 -0
  696. package/dist/frontend/ts7/ast-schema.generated.js +1446 -0
  697. package/dist/frontend/ts7/ast-schema.generated.js.map +1 -0
  698. package/dist/frontend/ts7/ast-text.d.ts +6 -0
  699. package/dist/frontend/ts7/ast-text.js +124 -0
  700. package/dist/frontend/ts7/ast-text.js.map +1 -0
  701. package/dist/frontend/ts7/ast-text.test.d.ts +1 -0
  702. package/dist/frontend/ts7/ast-text.test.js +38 -0
  703. package/dist/frontend/ts7/ast-text.test.js.map +1 -0
  704. package/dist/frontend/ts7/ast-tokens.generated.d.ts +2 -0
  705. package/dist/frontend/ts7/ast-tokens.generated.js +155 -0
  706. package/dist/frontend/ts7/ast-tokens.generated.js.map +1 -0
  707. package/dist/frontend/ts7/ast-types.d.ts +42 -0
  708. package/dist/frontend/ts7/ast-types.generated.d.ts +1615 -0
  709. package/dist/frontend/ts7/ast-types.generated.js +5 -0
  710. package/dist/frontend/ts7/ast-types.generated.js.map +1 -0
  711. package/dist/frontend/ts7/ast-types.js +3 -0
  712. package/dist/frontend/ts7/ast-types.js.map +1 -0
  713. package/dist/frontend/ts7/ast-wire.d.ts +58 -0
  714. package/dist/frontend/ts7/ast-wire.js +267 -0
  715. package/dist/frontend/ts7/ast-wire.js.map +1 -0
  716. package/dist/frontend/ts7/ast-wire.test.d.ts +1 -0
  717. package/dist/frontend/ts7/ast-wire.test.js +151 -0
  718. package/dist/frontend/ts7/ast-wire.test.js.map +1 -0
  719. package/dist/frontend/ts7/ast.d.ts +14 -14
  720. package/dist/frontend/ts7/ast.js +21 -15
  721. package/dist/frontend/ts7/ast.js.map +1 -1
  722. package/dist/frontend/ts7/census-check.js +1 -0
  723. package/dist/frontend/ts7/census-check.js.map +1 -1
  724. package/dist/frontend/ts7/checker-cache.d.ts +48 -0
  725. package/dist/frontend/ts7/checker-cache.js +92 -0
  726. package/dist/frontend/ts7/checker-cache.js.map +1 -0
  727. package/dist/frontend/ts7/checker.d.ts +19 -46
  728. package/dist/frontend/ts7/checker.js +231 -161
  729. package/dist/frontend/ts7/checker.js.map +1 -1
  730. package/dist/frontend/ts7/checker.test.d.ts +1 -0
  731. package/dist/frontend/ts7/checker.test.js +335 -0
  732. package/dist/frontend/ts7/checker.test.js.map +1 -0
  733. package/dist/frontend/ts7/enums.d.ts +4 -27
  734. package/dist/frontend/ts7/enums.generated.d.ts +878 -0
  735. package/dist/frontend/ts7/enums.generated.js +1313 -0
  736. package/dist/frontend/ts7/enums.generated.js.map +1 -0
  737. package/dist/frontend/ts7/enums.js +4 -45
  738. package/dist/frontend/ts7/enums.js.map +1 -1
  739. package/dist/frontend/ts7/enums.test.d.ts +1 -0
  740. package/dist/frontend/ts7/enums.test.js +48 -0
  741. package/dist/frontend/ts7/enums.test.js.map +1 -0
  742. package/dist/frontend/ts7/native-api.d.ts +10 -0
  743. package/dist/frontend/ts7/native-api.js +10 -0
  744. package/dist/frontend/ts7/native-api.js.map +1 -0
  745. package/dist/frontend/ts7/native-host.d.ts +2 -0
  746. package/dist/frontend/ts7/native-host.js +11 -0
  747. package/dist/frontend/ts7/native-host.js.map +1 -0
  748. package/dist/frontend/ts7/native-process.d.ts +14 -0
  749. package/dist/frontend/ts7/native-process.js +62 -0
  750. package/dist/frontend/ts7/native-process.js.map +1 -0
  751. package/dist/frontend/ts7/program-adapter.d.ts +10 -98
  752. package/dist/frontend/ts7/program-adapter.js +16 -310
  753. package/dist/frontend/ts7/program-adapter.js.map +1 -1
  754. package/dist/frontend/ts7/program-host.d.ts +115 -0
  755. package/dist/frontend/ts7/program-host.js +347 -0
  756. package/dist/frontend/ts7/program-host.js.map +1 -0
  757. package/dist/frontend/ts7/program-host.test.d.ts +1 -0
  758. package/dist/frontend/ts7/program-host.test.js +207 -0
  759. package/dist/frontend/ts7/program-host.test.js.map +1 -0
  760. package/dist/frontend/ts7/rpc-api.d.ts +12 -0
  761. package/dist/frontend/ts7/rpc-api.js +23 -0
  762. package/dist/frontend/ts7/rpc-api.js.map +1 -0
  763. package/dist/frontend/ts7/rpc-client.d.ts +27 -0
  764. package/dist/frontend/ts7/rpc-client.js +102 -0
  765. package/dist/frontend/ts7/rpc-client.js.map +1 -0
  766. package/dist/frontend/ts7/rpc-client.test.d.ts +1 -0
  767. package/dist/frontend/ts7/rpc-client.test.js +133 -0
  768. package/dist/frontend/ts7/rpc-client.test.js.map +1 -0
  769. package/dist/frontend/ts7/rpc-filesystem.d.ts +16 -0
  770. package/dist/frontend/ts7/rpc-filesystem.js +42 -0
  771. package/dist/frontend/ts7/rpc-filesystem.js.map +1 -0
  772. package/dist/frontend/ts7/rpc-filesystem.test.d.ts +1 -0
  773. package/dist/frontend/ts7/rpc-filesystem.test.js +89 -0
  774. package/dist/frontend/ts7/rpc-filesystem.test.js.map +1 -0
  775. package/dist/frontend/ts7/rpc-process.d.ts +2 -0
  776. package/dist/frontend/ts7/rpc-process.js +148 -0
  777. package/dist/frontend/ts7/rpc-process.js.map +1 -0
  778. package/dist/frontend/ts7/rpc-process.test.d.ts +1 -0
  779. package/dist/frontend/ts7/rpc-process.test.js +29 -0
  780. package/dist/frontend/ts7/rpc-process.test.js.map +1 -0
  781. package/dist/frontend/ts7/rpc-wire.d.ts +46 -0
  782. package/dist/frontend/ts7/rpc-wire.js +195 -0
  783. package/dist/frontend/ts7/rpc-wire.js.map +1 -0
  784. package/dist/frontend/ts7/rpc-wire.test.d.ts +1 -0
  785. package/dist/frontend/ts7/rpc-wire.test.js +168 -0
  786. package/dist/frontend/ts7/rpc-wire.test.js.map +1 -0
  787. package/dist/frontend/ts7/semantic-checker.d.ts +137 -0
  788. package/dist/frontend/ts7/semantic-checker.js +221 -0
  789. package/dist/frontend/ts7/semantic-checker.js.map +1 -0
  790. package/dist/frontend/ts7/semantic-checker.test.d.ts +1 -0
  791. package/dist/frontend/ts7/semantic-checker.test.js +119 -0
  792. package/dist/frontend/ts7/semantic-checker.test.js.map +1 -0
  793. package/dist/frontend/ts7/semantic-json.d.ts +5 -0
  794. package/dist/frontend/ts7/semantic-json.js +52 -0
  795. package/dist/frontend/ts7/semantic-json.js.map +1 -0
  796. package/dist/frontend/ts7/semantic-json.test.d.ts +1 -0
  797. package/dist/frontend/ts7/semantic-json.test.js +42 -0
  798. package/dist/frontend/ts7/semantic-json.test.js.map +1 -0
  799. package/dist/frontend/ts7/semantic-model.d.ts +222 -0
  800. package/dist/frontend/ts7/semantic-model.js +423 -0
  801. package/dist/frontend/ts7/semantic-model.js.map +1 -0
  802. package/dist/frontend/ts7/semantic-model.test.d.ts +1 -0
  803. package/dist/frontend/ts7/semantic-model.test.js +322 -0
  804. package/dist/frontend/ts7/semantic-model.test.js.map +1 -0
  805. package/dist/frontend/ts7/semantic-schema.generated.d.ts +283 -0
  806. package/dist/frontend/ts7/semantic-schema.generated.js +222 -0
  807. package/dist/frontend/ts7/semantic-schema.generated.js.map +1 -0
  808. package/dist/frontend/ts7/semantic-types.d.ts +5 -0
  809. package/dist/frontend/ts7/semantic-types.js +2 -0
  810. package/dist/frontend/ts7/semantic-types.js.map +1 -0
  811. package/dist/frontend/ts7/session-cache.d.ts +17 -0
  812. package/dist/frontend/ts7/session-cache.js +97 -0
  813. package/dist/frontend/ts7/session-cache.js.map +1 -0
  814. package/dist/frontend/ts7/session-cache.test.d.ts +1 -0
  815. package/dist/frontend/ts7/session-cache.test.js +87 -0
  816. package/dist/frontend/ts7/session-cache.test.js.map +1 -0
  817. package/dist/frontend/ts7/session-path.d.ts +18 -0
  818. package/dist/frontend/ts7/session-path.js +203 -0
  819. package/dist/frontend/ts7/session-path.js.map +1 -0
  820. package/dist/frontend/ts7/session-path.test.d.ts +1 -0
  821. package/dist/frontend/ts7/session-path.test.js +34 -0
  822. package/dist/frontend/ts7/session-path.test.js.map +1 -0
  823. package/dist/frontend/ts7/session-schema.generated.d.ts +167 -0
  824. package/dist/frontend/ts7/session-schema.generated.js +5 -0
  825. package/dist/frontend/ts7/session-schema.generated.js.map +1 -0
  826. package/dist/frontend/ts7/session-timing.d.ts +50 -0
  827. package/dist/frontend/ts7/session-timing.js +61 -0
  828. package/dist/frontend/ts7/session-timing.js.map +1 -0
  829. package/dist/frontend/ts7/session-timing.test.d.ts +1 -0
  830. package/dist/frontend/ts7/session-timing.test.js +52 -0
  831. package/dist/frontend/ts7/session-timing.test.js.map +1 -0
  832. package/dist/frontend/ts7/session.d.ts +105 -0
  833. package/dist/frontend/ts7/session.js +233 -0
  834. package/dist/frontend/ts7/session.js.map +1 -0
  835. package/dist/frontend/ts7/session.test.d.ts +1 -0
  836. package/dist/frontend/ts7/session.test.js +215 -0
  837. package/dist/frontend/ts7/session.test.js.map +1 -0
  838. package/dist/frontend/ts7/source-parser-node.d.ts +6 -0
  839. package/dist/frontend/ts7/source-parser-node.js +15 -0
  840. package/dist/frontend/ts7/source-parser-node.js.map +1 -0
  841. package/dist/frontend/ts7/source-parser.d.ts +25 -0
  842. package/dist/frontend/ts7/source-parser.js +96 -0
  843. package/dist/frontend/ts7/source-parser.js.map +1 -0
  844. package/dist/frontend/ts7/source-parser.test.d.ts +1 -0
  845. package/dist/frontend/ts7/source-parser.test.js +151 -0
  846. package/dist/frontend/ts7/source-parser.test.js.map +1 -0
  847. package/dist/frontend/ts7/syntax.d.ts +3 -0
  848. package/dist/frontend/ts7/syntax.js +4 -0
  849. package/dist/frontend/ts7/syntax.js.map +1 -0
  850. package/dist/frontend/tsc-codes.js +3 -0
  851. package/dist/frontend/tsc-codes.js.map +1 -1
  852. package/dist/frontend/type-mapper.d.ts +25 -17
  853. package/dist/frontend/type-mapper.js +465 -121
  854. package/dist/frontend/type-mapper.js.map +1 -1
  855. package/dist/frontend/type-mapper.test.js +123 -2
  856. package/dist/frontend/type-mapper.test.js.map +1 -1
  857. package/dist/frontend/union-discriminants.d.ts +16 -0
  858. package/dist/frontend/union-discriminants.js +98 -0
  859. package/dist/frontend/union-discriminants.js.map +1 -0
  860. package/dist/frontend/union-discriminants.test.d.ts +1 -0
  861. package/dist/frontend/union-discriminants.test.js +182 -0
  862. package/dist/frontend/union-discriminants.test.js.map +1 -0
  863. package/dist/index.d.ts +7 -198
  864. package/dist/index.js +369 -1572
  865. package/dist/index.js.map +1 -1
  866. package/dist/ir/analysis.d.ts +16 -4
  867. package/dist/ir/analysis.js +21 -4
  868. package/dist/ir/analysis.js.map +1 -1
  869. package/dist/ir/analysis.test.js +15 -2
  870. package/dist/ir/analysis.test.js.map +1 -1
  871. package/dist/ir/constant-tables.js +67 -49
  872. package/dist/ir/constant-tables.js.map +1 -1
  873. package/dist/ir/constant-tables.test.js +1 -1
  874. package/dist/ir/control-flow.d.ts +6 -0
  875. package/dist/ir/control-flow.js +142 -0
  876. package/dist/ir/control-flow.js.map +1 -0
  877. package/dist/ir/control-flow.test.d.ts +1 -0
  878. package/dist/ir/control-flow.test.js +113 -0
  879. package/dist/ir/control-flow.test.js.map +1 -0
  880. package/dist/ir/integer-loops.js +7 -18
  881. package/dist/ir/integer-loops.js.map +1 -1
  882. package/dist/ir/integer-ranges.js +53 -27
  883. package/dist/ir/integer-ranges.js.map +1 -1
  884. package/dist/ir/ir.d.ts +291 -152
  885. package/dist/ir/ir.js +588 -881
  886. package/dist/ir/ir.js.map +1 -1
  887. package/dist/ir/ir.test.js +127 -1
  888. package/dist/ir/ir.test.js.map +1 -1
  889. package/dist/ir/scalar-records.js +165 -134
  890. package/dist/ir/scalar-records.js.map +1 -1
  891. package/dist/ir/scalar-records.test.js +1 -1
  892. package/dist/ir/serialize.d.ts +4 -2
  893. package/dist/ir/serialize.js +19 -12
  894. package/dist/ir/serialize.js.map +1 -1
  895. package/dist/ir/serialize.test.d.ts +1 -0
  896. package/dist/ir/serialize.test.js +53 -0
  897. package/dist/ir/serialize.test.js.map +1 -0
  898. package/dist/ir/traverse.d.ts +41 -0
  899. package/dist/ir/traverse.js +660 -0
  900. package/dist/ir/traverse.js.map +1 -0
  901. package/dist/ir/traverse.test.d.ts +1 -0
  902. package/dist/ir/traverse.test.js +242 -0
  903. package/dist/ir/traverse.test.js.map +1 -0
  904. package/dist/ir/validate.js +1942 -1491
  905. package/dist/ir/validate.js.map +1 -1
  906. package/dist/ir/validate.test.js +476 -2
  907. package/dist/ir/validate.test.js.map +1 -1
  908. package/dist/library/cache-primitives.d.ts +2 -3
  909. package/dist/library/cache-primitives.js +4 -6
  910. package/dist/library/cache-primitives.js.map +1 -1
  911. package/dist/library/fence-eval.js +2 -2
  912. package/dist/library/fence-eval.js.map +1 -1
  913. package/dist/library/int-infer.js +7 -6
  914. package/dist/library/int-infer.js.map +1 -1
  915. package/dist/library/int-infer.test.js +4 -4
  916. package/dist/library/library-cache.d.ts +3 -2
  917. package/dist/library/library-cache.js +5 -17
  918. package/dist/library/library-cache.js.map +1 -1
  919. package/dist/library/library-cache.test.js +54 -41
  920. package/dist/library/library-cache.test.js.map +1 -1
  921. package/dist/library/library-profile.d.ts +3 -1
  922. package/dist/library/library-profile.js +15 -6
  923. package/dist/library/library-profile.js.map +1 -1
  924. package/dist/library/prepare.d.ts +15 -0
  925. package/dist/library/prepare.js +584 -0
  926. package/dist/library/prepare.js.map +1 -0
  927. package/dist/library/semantic-source.d.ts +1 -1
  928. package/dist/library/semantic-source.js +8 -6
  929. package/dist/library/semantic-source.js.map +1 -1
  930. package/dist/library/sidecar-validate.js +4 -4
  931. package/dist/library/sidecar-validate.js.map +1 -1
  932. package/dist/library/sidecar.d.ts +2 -0
  933. package/dist/library/sidecar.js +10 -3
  934. package/dist/library/sidecar.js.map +1 -1
  935. package/dist/native/cache.d.ts +11 -0
  936. package/dist/native/cache.js +113 -0
  937. package/dist/native/cache.js.map +1 -0
  938. package/dist/native/cache.test.d.ts +1 -0
  939. package/dist/native/cache.test.js +66 -0
  940. package/dist/native/cache.test.js.map +1 -0
  941. package/dist/native/cli.d.ts +1 -0
  942. package/dist/native/cli.js +112 -0
  943. package/dist/native/cli.js.map +1 -0
  944. package/dist/native/compiler.d.ts +15 -0
  945. package/dist/native/compiler.js +336 -0
  946. package/dist/native/compiler.js.map +1 -0
  947. package/dist/native/compiler.test.d.ts +1 -0
  948. package/dist/native/compiler.test.js +174 -0
  949. package/dist/native/compiler.test.js.map +1 -0
  950. package/dist/native/comptime.d.ts +5 -0
  951. package/dist/native/comptime.js +73 -0
  952. package/dist/native/comptime.js.map +1 -0
  953. package/dist/native/comptime.test.d.ts +1 -0
  954. package/dist/native/comptime.test.js +65 -0
  955. package/dist/native/comptime.test.js.map +1 -0
  956. package/dist/native/executable-cache.d.ts +26 -0
  957. package/dist/native/executable-cache.js +228 -0
  958. package/dist/native/executable-cache.js.map +1 -0
  959. package/dist/native/executable-cache.test.d.ts +1 -0
  960. package/dist/native/executable-cache.test.js +151 -0
  961. package/dist/native/executable-cache.test.js.map +1 -0
  962. package/dist/native/file-identity.d.ts +4 -0
  963. package/dist/native/file-identity.js +14 -0
  964. package/dist/native/file-identity.js.map +1 -0
  965. package/dist/native/file-identity.test.d.ts +1 -0
  966. package/dist/native/file-identity.test.js +43 -0
  967. package/dist/native/file-identity.test.js.map +1 -0
  968. package/dist/native/library.d.ts +22 -0
  969. package/dist/native/library.js +83 -0
  970. package/dist/native/library.js.map +1 -0
  971. package/dist/native/prepare.d.ts +21 -0
  972. package/dist/native/prepare.js +174 -0
  973. package/dist/native/prepare.js.map +1 -0
  974. package/dist/native/prepare.test.d.ts +1 -0
  975. package/dist/native/prepare.test.js +70 -0
  976. package/dist/native/prepare.test.js.map +1 -0
  977. package/dist/native/sanitizer.d.ts +11 -0
  978. package/dist/native/sanitizer.js +135 -0
  979. package/dist/native/sanitizer.js.map +1 -0
  980. package/dist/native/sanitizer.test.d.ts +1 -0
  981. package/dist/native/sanitizer.test.js +58 -0
  982. package/dist/native/sanitizer.test.js.map +1 -0
  983. package/dist/native/task.d.ts +4 -0
  984. package/dist/native/task.js +16 -0
  985. package/dist/native/task.js.map +1 -0
  986. package/dist/native/task.test.d.ts +1 -0
  987. package/dist/native/task.test.js +17 -0
  988. package/dist/native/task.test.js.map +1 -0
  989. package/dist/native/toolchain.d.ts +45 -0
  990. package/dist/native/toolchain.js +74 -0
  991. package/dist/native/toolchain.js.map +1 -0
  992. package/dist/native/toolchain.test.d.ts +1 -0
  993. package/dist/native/toolchain.test.js +33 -0
  994. package/dist/native/toolchain.test.js.map +1 -0
  995. package/dist/startup-cache.d.ts +1 -1
  996. package/dist/startup-cache.js +2 -5
  997. package/dist/startup-cache.js.map +1 -1
  998. package/dist/timing.d.ts +4 -0
  999. package/dist/timing.js +19 -0
  1000. package/dist/timing.js.map +1 -0
  1001. package/dist/wasi-paths.js +10 -7
  1002. package/dist/wasi-paths.js.map +1 -1
  1003. package/package.json +28 -19
  1004. package/surface-manifest.json +52 -18
  1005. package/dist/backend/c/async.d.ts +0 -171
  1006. package/dist/backend/c/async.js +0 -1317
  1007. package/dist/backend/c/async.js.map +0 -1
  1008. package/dist/backend/c/c-emitter.d.ts +0 -536
  1009. package/dist/backend/c/c-emitter.js +0 -1932
  1010. package/dist/backend/c/c-emitter.js.map +0 -1
  1011. package/dist/backend/c/exprs.d.ts +0 -15
  1012. package/dist/backend/c/exprs.js +0 -8847
  1013. package/dist/backend/c/exprs.js.map +0 -1
  1014. package/dist/backend/c/island.d.ts +0 -45
  1015. package/dist/backend/c/island.js +0 -281
  1016. package/dist/backend/c/island.js.map +0 -1
  1017. package/dist/backend/c/may-throw.js.map +0 -1
  1018. package/dist/backend/c/shapes.d.ts +0 -142
  1019. package/dist/backend/c/shapes.js +0 -603
  1020. package/dist/backend/c/shapes.js.map +0 -1
  1021. package/dist/backend/c/stmts.d.ts +0 -76
  1022. package/dist/backend/c/stmts.js +0 -1108
  1023. package/dist/backend/c/stmts.js.map +0 -1
  1024. package/dist/backend/c/types.d.ts +0 -71
  1025. package/dist/backend/c/types.js +0 -459
  1026. package/dist/backend/c/types.js.map +0 -1
  1027. package/dist/backend/c/types.test.js +0 -32
  1028. package/dist/backend/c/types.test.js.map +0 -1
  1029. package/dist/backend/c/walkers.d.ts +0 -134
  1030. package/dist/backend/c/walkers.js +0 -1772
  1031. package/dist/backend/c/walkers.js.map +0 -1
  1032. /package/dist/backend/{c/types.test.d.ts → cycle-analysis.test.d.ts} +0 -0
@@ -1,5 +1,7 @@
1
- import { arrayOf, BOOL, BYTES_U8, bytesOf, canAdaptDynFuncTo, canConvertToDyn, canExitIslandToType, canMarshalIntoIsland, canMarshalTypedFuncIntoIsland, CHILD_T, CHILDSTREAM_T, CHILDWRITER_T, CRYPTOHASH_T, CRYPTOHMAC_T, DATE_T, DGRAMSOCK_T, DYN, DYN_HANDLE_KINDS, F64, ffiClassType, ffiSourceParamTypes, FILEHANDLE_T, FSWATCHER_T, HTTP2SESSION_T, HTTP2STREAM_T, HTTPCLIENTREQ_T, HTTPREQ_T, HTTPRES_T, islandPromisePayloadTag, isDynTypedRefType, isFfiCallbackParam, isFfiContextParam, isFfiReleaseParam, isJsonSafeType, isJsonStringifySafeType, isRefCounted, isSupportedArrayElem, isSupportedIndexValue, isSupportedMapKey, isSupportedMapValue, isSupportedSetElem, isUnitType, jsOpResultKind, JSVAL, NETSERVER_T, NETSOCKET_T, PROCSTREAM_T, REF_TRUTHY_KINDS, REGEX, RUNTIME_EMITTER_CLASS, RUNTIME_ERROR_CLASSES, RUNTIME_STREAM_CLASSES, SEARCH_PARAMS_T, SECURECTX_T, shapeHasAccessorSlots, SPAWNRES_T, STATS_T, STRING, SYMBOL_T, TESTCTX_T, typeEquals, typeKey, unionFuncSetArmsOk, URL_T, VOID } from "./ir.js";
1
+ import { arrayOf, BYTES_ELEMENT_NAME, BOOL, BYTES_U8, bytesOf, canAdaptDynFuncTo, canDynCheckTo, canConvertToDyn, canExitIslandToType, canMarshalIntoIsland, canMarshalTypedFuncIntoIsland, CHILD_T, CHILDSTREAM_T, CHILDWRITER_T, CRYPTOHASH_T, CRYPTOHMAC_T, DATE_T, DGRAMSOCK_T, DYN, DYN_HANDLE_KINDS, F64, ffiClassType, ffiSourceParamTypes, FILEHANDLE_T, FSWATCHER_T, HTTP2SESSION_T, HTTP2STREAM_T, HTTPCLIENTREQ_T, HTTPREQ_T, HTTPRES_T, islandPromisePayloadTag, isDynTypedRefType, isFfiCallbackParam, isFfiContextParam, isFfiReleaseParam, isJsonSafeType, isJsonStringifySafeType, isRefCounted, isSupportedArrayElem, isSupportedIndexValue, isSupportedMapKey, isSupportedMapValue, isSupportedSetElem, isUnitType, jsOpResultKind, JSVAL, NETSERVER_T, NETSOCKET_T, PROCSTREAM_T, REF_TRUTHY_KINDS, REGEX, RUNTIME_EMITTER_CLASS, RUNTIME_ERROR_CLASSES, RUNTIME_STREAM_CLASSES, SEARCH_PARAMS_T, SECURECTX_T, shapeHasAccessorSlots, SPAWNRES_T, STATS_T, STRING, SYMBOL_T, TESTCTX_T, typeEquals, typeKey, unionContainerArmsOk, URL_T, VOID } from "./ir.js";
2
2
  import { BIGINT_T } from "./ir.js";
3
+ import { unionWideningTags } from "./analysis.js";
4
+ import { alwaysReturns } from "./control-flow.js";
3
5
  /** Per-method signature for strIntrinsic: `argTypes` lists every argument
4
6
  * position (optional ones included); `minArgs` is how many may be omitted
5
7
  * from the end (backends fill the documented defaults). Exported for the
@@ -43,6 +45,7 @@ export const REGEX_INTRINSIC_SIGS = {
43
45
  search: { receiver: STRING, argTypes: [REGEX], result: F64 },
44
46
  source: { receiver: REGEX, argTypes: [], result: STRING },
45
47
  flags: { receiver: REGEX, argTypes: [], result: STRING },
48
+ toString: { receiver: REGEX, argTypes: [], result: STRING },
46
49
  replace: { receiver: STRING, argTypes: [REGEX, STRING], result: STRING },
47
50
  replaceAll: { receiver: STRING, argTypes: [REGEX, STRING], result: STRING },
48
51
  split: { receiver: STRING, argTypes: [REGEX, F64], result: arrayOf(STRING) },
@@ -57,6 +60,7 @@ export const REGEX_INTRINSIC_SIGS = {
57
60
  export const LIB_FN_SIGS = {
58
61
  "fetch.start": { argTypes: [STRING, DYN], result: { kind: "promise", inner: DYN } },
59
62
  "fetch.responseNew": { argTypes: [DYN, DYN], result: DYN },
63
+ "fetch.responseArrayBuffer": { argTypes: [DYN], result: { kind: "promise", inner: DYN } },
60
64
  "fetch.responseJson": { argTypes: [DYN], result: { kind: "promise", inner: DYN } },
61
65
  "fetch.responseText": { argTypes: [DYN], result: { kind: "promise", inner: STRING } },
62
66
  "fetch.responseBytes": { argTypes: [DYN], result: { kind: "promise", inner: BYTES_U8 } },
@@ -78,13 +82,45 @@ export const LIB_FN_SIGS = {
78
82
  // checked in the libCall case, like error.new.
79
83
  "island.castFail": { argTypes: [JSVAL, STRING], result: VOID },
80
84
  "json.parse": { argTypes: [STRING], result: DYN },
85
+ "json.parseReviver": { argTypes: [STRING, DYN], result: DYN },
86
+ "json.stringifyReplacer": { argTypes: [DYN, DYN, STRING], result: DYN },
87
+ "json.stringifyValue": { argTypes: [DYN, DYN, DYN], result: DYN },
81
88
  "dyn.keySet": { argTypes: [DYN, STRING, DYN], result: VOID },
89
+ "dyn.keySetComputed": { argTypes: [DYN, DYN, DYN], result: VOID },
90
+ "dyn.keyDelete": { argTypes: [DYN, STRING, BOOL], result: VOID },
91
+ "dyn.keyDeleteComputed": { argTypes: [DYN, DYN, BOOL], result: VOID },
92
+ "dyn.hasKeyComputed": { argTypes: [DYN, DYN], result: BOOL },
93
+ "dyn.hasOwnComputed": { argTypes: [DYN, DYN], result: BOOL },
94
+ "dyn.propertyIsEnumerableComputed": { argTypes: [DYN, DYN], result: BOOL },
95
+ "dyn.globalSymbolGet": { argTypes: [SYMBOL_T], result: DYN },
96
+ "dyn.globalSymbolSet": { argTypes: [SYMBOL_T, DYN], result: VOID },
97
+ "dyn.globalSymbolHas": { argTypes: [SYMBOL_T], result: BOOL },
98
+ "dyn.globalSymbolDelete": { argTypes: [SYMBOL_T], result: VOID },
99
+ "dyn.typedRefIs": { argTypes: [DYN, STRING], result: BOOL },
82
100
  "dyn.iterPack": { argTypes: [DYN, STRING], result: DYN },
101
+ "dyn.arrayFromIterator": { argTypes: [DYN], result: DYN },
102
+ "dyn.iterator": { argTypes: [DYN, STRING], result: DYN },
103
+ "dyn.iteratorResult": { argTypes: [DYN], result: DYN },
104
+ "dyn.mapSeedEntries": { argTypes: [DYN], result: DYN },
105
+ "dyn.mapSeedEntry": { argTypes: [DYN], result: DYN },
83
106
  "dyn.arrLen": { argTypes: [DYN], result: F64 },
84
107
  "dyn.arrAt": { argTypes: [DYN, F64], result: DYN },
85
108
  "dyn.hasKey": { argTypes: [DYN, STRING], result: BOOL },
86
- "dyn.toString": { argTypes: [DYN, STRING, STRING], result: STRING },
109
+ "dyn.freeze": { argTypes: [DYN], result: DYN },
110
+ "dyn.isFrozen": { argTypes: [DYN], result: BOOL },
111
+ "dyn.nativeSetNew": { argTypes: [DYN], result: DYN },
112
+ "dyn.nativeSetIs": { argTypes: [DYN], result: BOOL },
113
+ "dyn.nativeMapIs": { argTypes: [DYN], result: BOOL },
114
+ "dyn.nativeUrlIs": { argTypes: [DYN], result: BOOL },
115
+ "dyn.nativeDateIs": { argTypes: [DYN], result: BOOL },
116
+ "date.nativeNew": { argTypes: [DYN], result: DYN },
117
+ "date.checkedValue": { argTypes: [DYN], result: DATE_T },
118
+ "dyn.nativeRegexIs": { argTypes: [DYN], result: BOOL },
119
+ "dyn.toString": { argTypes: [DYN, DYN, STRING], result: STRING },
87
120
  "dyn.defineProps": { argTypes: [DYN, DYN], result: DYN },
121
+ "dyn.defineProperty": { argTypes: [DYN, DYN, DYN], result: DYN },
122
+ "dyn.getOwnPropertyDescriptor": { argTypes: [DYN, DYN], result: DYN },
123
+ "dyn.arrayProtoCall": { argTypes: [DYN, STRING, DYN], result: DYN },
88
124
  "dyn.typeof": { argTypes: [DYN], result: STRING },
89
125
  "dyn.objectTag": { argTypes: [DYN], result: STRING },
90
126
  "module.registryInit": { argTypes: [F64], result: VOID },
@@ -139,8 +175,8 @@ export const LIB_FN_SIGS = {
139
175
  // Signal listeners are zero-param (the ambient shape); exit/stdin
140
176
  // callbacks carry program-dependent one-param shapes — null slots, the
141
177
  // libCall case checks them (child.onExit precedent).
142
- "process.onSignal": { argTypes: [F64, { kind: "func", params: [], ret: VOID }, BOOL], result: VOID },
143
- "process.offSignal": { argTypes: [F64, { kind: "func", params: [], ret: VOID }], result: VOID },
178
+ "process.onSignal": { argTypes: [STRING, DYN, BOOL], result: VOID },
179
+ "process.offSignal": { argTypes: [STRING, DYN], result: VOID },
144
180
  "process.onExit": { argTypes: [null, BOOL], result: VOID },
145
181
  "process.offExit": { argTypes: [null], result: VOID },
146
182
  "stdin.onData": { argTypes: [null, BOOL], result: VOID },
@@ -188,6 +224,7 @@ export const LIB_FN_SIGS = {
188
224
  "net.getAutoSelTimeout": { argTypes: [], result: F64 },
189
225
  "net.setAutoSelTimeout": { argTypes: [F64], result: VOID },
190
226
  "fs.realpathSync": { argTypes: [STRING], result: STRING },
227
+ "fs.realpathNativeSync": { argTypes: [STRING], result: STRING },
191
228
  "os.userName": { argTypes: [], result: STRING },
192
229
  "os.userShell": { argTypes: [], result: STRING },
193
230
  "os.userHomedir": { argTypes: [], result: STRING },
@@ -253,6 +290,7 @@ export const LIB_FN_SIGS = {
253
290
  "sym.new": { argTypes: [STRING], result: SYMBOL_T },
254
291
  "sym.newAnon": { argTypes: [], result: SYMBOL_T },
255
292
  "sym.for": { argTypes: [STRING], result: SYMBOL_T },
293
+ "sym.wellKnown": { argTypes: [STRING], result: SYMBOL_T },
256
294
  // Result is the interned `string | undefined` union — the libCall case
257
295
  // checks the arms (the spawnRes.error pattern).
258
296
  "sym.keyFor": { argTypes: [SYMBOL_T], result: VOID },
@@ -288,6 +326,7 @@ export const LIB_FN_SIGS = {
288
326
  "bigint.dataViewGet": { argTypes: [BYTES_U8, F64, BOOL, BOOL], result: BIGINT_T },
289
327
  "bigint.dataViewSet": { argTypes: [BYTES_U8, F64, BIGINT_T, BOOL], result: VOID },
290
328
  "url.new": { argTypes: [STRING], result: URL_T },
329
+ "url.newBase": { argTypes: [STRING, STRING], result: URL_T },
291
330
  "url.protocol": { argTypes: [URL_T], result: STRING },
292
331
  "url.origin": { argTypes: [URL_T], result: STRING },
293
332
  "url.username": { argTypes: [URL_T], result: STRING },
@@ -298,8 +337,10 @@ export const LIB_FN_SIGS = {
298
337
  "url.pathname": { argTypes: [URL_T], result: STRING },
299
338
  "url.href": { argTypes: [URL_T], result: STRING },
300
339
  "url.fileURLToPathUrl": { argTypes: [URL_T], result: STRING },
340
+ "url.fileURLToPathChecked": { argTypes: [DYN], result: STRING },
301
341
  "url.fileURLToPathStr": { argTypes: [STRING], result: STRING },
302
342
  "url.pathToFileURL": { argTypes: [STRING], result: URL_T },
343
+ "url.pathToFileURLPlatform": { argTypes: [STRING, BOOL], result: URL_T },
303
344
  "url.pathToFileURLWin32": { argTypes: [STRING], result: URL_T },
304
345
  "sp.new": { argTypes: [], result: SEARCH_PARAMS_T },
305
346
  "sp.parse": { argTypes: [STRING], result: SEARCH_PARAMS_T },
@@ -909,6 +950,8 @@ export const LIB_FN_SIGS = {
909
950
  // The Buffer statics and the fs/zlib Buffer forms: fixed always-u8
910
951
  // signatures (Buffer IS a Uint8Array — one bytes kind).
911
952
  "buffer.fromStr": { argTypes: [STRING, STRING], result: BYTES_U8 },
953
+ "buffer.brand": { argTypes: [BYTES_U8], result: BYTES_U8 },
954
+ "buffer.fromDyn": { argTypes: [DYN, STRING], result: BYTES_U8 },
912
955
  "buffer.concat": { argTypes: [arrayOf(BYTES_U8)], result: BYTES_U8 },
913
956
  "buffer.byteLenStr": { argTypes: [STRING, STRING], result: F64 },
914
957
  "buffer.isEncoding": { argTypes: [STRING], result: BOOL },
@@ -937,10 +980,12 @@ export const LIB_FN_SIGS = {
937
980
  "emitter.setDefaultMaxChk": { argTypes: [DYN, STRING], result: VOID },
938
981
  "fs.readFileSyncBytes": { argTypes: [STRING], result: BYTES_U8 },
939
982
  "fs.writeFileSyncBytes": { argTypes: [STRING, BYTES_U8], result: VOID },
983
+ "fs.appendFileSyncBytes": { argTypes: [STRING, BYTES_U8], result: VOID },
940
984
  "fsp.readFileBytes": { argTypes: [STRING], result: { kind: "promise", inner: BYTES_U8 } },
941
985
  "zlib.deflateSync": { argTypes: [BYTES_U8], result: BYTES_U8 },
942
986
  "zlib.inflateSync": { argTypes: [BYTES_U8], result: BYTES_U8 },
943
987
  "zlib.deflateRawSync": { argTypes: [BYTES_U8], result: BYTES_U8 },
988
+ "zlib.deflateLevelSync": { argTypes: [BYTES_U8, F64, F64], result: BYTES_U8 },
944
989
  "zlib.inflateRawSync": { argTypes: [BYTES_U8], result: BYTES_U8 },
945
990
  "zlib.gzipSync": { argTypes: [BYTES_U8], result: BYTES_U8 },
946
991
  "zlib.gunzipSync": { argTypes: [BYTES_U8], result: BYTES_U8 },
@@ -1010,26 +1055,52 @@ export const LIB_FN_SIGS = {
1010
1055
  "process.getgid": { argTypes: [], result: F64 },
1011
1056
  "process.execPath": { argTypes: [], result: STRING },
1012
1057
  "process.arch": { argTypes: [], result: STRING },
1058
+ "process.versions": { argTypes: [], result: DYN },
1059
+ "process.builtinId": { argTypes: [DYN, arrayOf(STRING)], result: STRING },
1060
+ "process.builtinModule": { argTypes: [STRING, DYN], result: DYN },
1061
+ "process.builtinUnsupported": { argTypes: [STRING, STRING], result: DYN },
1062
+ "process.hrtimeValue": { argTypes: [], result: DYN },
1013
1063
  "process.versionsNode": { argTypes: [], result: STRING },
1014
1064
  "process.versionsOpenssl": { argTypes: [], result: STRING },
1015
1065
  "process.kill": { argTypes: [F64, STRING], result: BOOL },
1016
1066
  "process.killNum": { argTypes: [F64, F64], result: BOOL },
1017
1067
  "process.stdoutWrite": { argTypes: [STRING], result: BOOL },
1068
+ "process.stdio": { argTypes: [F64], result: DYN },
1018
1069
  "process.stderrWrite": { argTypes: [STRING], result: BOOL },
1019
1070
  // error.new's result and the receiver slots are builtin-error classes —
1020
1071
  // program-dependent object types, checked in the libCall case.
1021
1072
  "error.new": { argTypes: [STRING], result: VOID },
1073
+ "error.newOptions": { argTypes: [DYN, DYN], result: VOID },
1074
+ "error.ctorOptions": { argTypes: [null, DYN, DYN], result: VOID },
1075
+ "error.cause": { argTypes: [null], result: DYN },
1076
+ "error.hasCause": { argTypes: [null], result: BOOL },
1077
+ "error.setCause": { argTypes: [null, DYN], result: VOID },
1078
+ "error.deleteCause": { argTypes: [null], result: VOID },
1022
1079
  "error.nodeThrow": { argTypes: [F64, STRING, STRING], result: VOID },
1023
1080
  "dyn.toStringCoerce": { argTypes: [DYN], result: STRING },
1081
+ "dyn.stringConstructor": { argTypes: [DYN], result: STRING },
1082
+ "dyn.propertyKey": { argTypes: [DYN], result: DYN },
1083
+ "dyn.toNumeric": { argTypes: [DYN], result: DYN },
1084
+ "dyn.increment": { argTypes: [DYN, BOOL], result: DYN },
1085
+ "dyn.numberConstructor": { argTypes: [DYN], result: F64 },
1024
1086
  "dyn.toNumberCoerce": { argTypes: [DYN], result: F64 },
1087
+ "dyn.add": { argTypes: [DYN, DYN], result: DYN },
1088
+ "dyn.arithmetic": { argTypes: [DYN, DYN, STRING], result: DYN },
1089
+ "dyn.bitwise": { argTypes: [DYN, DYN, STRING], result: DYN },
1090
+ "dyn.proxyNew": { argTypes: [DYN, DYN], result: DYN },
1025
1091
  // Always throws; the result is the READ's declared type (a typed dummy
1026
1092
  // the unwind abandons) — the libCall case skips the result check.
1027
1093
  "global.undefRead": { argTypes: [STRING], result: VOID },
1094
+ "console.native": { argTypes: [], result: DYN },
1095
+ "global.native": { argTypes: [arrayOf(STRING)], result: DYN },
1028
1096
  // `X.name` through a class value: the arg is a program-dependent
1029
1097
  // classval (a null slot; the libCall case checks the kind).
1030
1098
  "class.name": { argTypes: [null], result: STRING },
1031
1099
  "error.ctor": { argTypes: [null, STRING], result: VOID },
1032
1100
  "error.toString": { argTypes: [null], result: STRING },
1101
+ "error.stack": { argTypes: [null], result: STRING },
1102
+ "error.stackLimitGet": { argTypes: [], result: F64 },
1103
+ "error.stackLimitSet": { argTypes: [F64], result: VOID },
1033
1104
  // Receiver (any error-hierarchy object) and the program-dependent
1034
1105
  // `string | undefined` result are checked in the libCall case.
1035
1106
  "error.code": { argTypes: [null], result: VOID },
@@ -1044,20 +1115,63 @@ export const LIB_FN_SIGS = {
1044
1115
  "error.domCause": { argTypes: [null], result: DYN },
1045
1116
  "error.domClone": { argTypes: [null, DYN], result: VOID },
1046
1117
  "dyn.errInstanceof": { argTypes: [DYN, F64], result: BOOL },
1118
+ "weakMap.is": { argTypes: [DYN], result: BOOL },
1119
+ "weakSet.is": { argTypes: [DYN], result: BOOL },
1120
+ "weakMap.new": { argTypes: [DYN], result: DYN },
1121
+ "weakSet.new": { argTypes: [DYN], result: DYN },
1122
+ "dyn.fromEntries": { argTypes: [DYN], result: DYN },
1123
+ "arrayBuffer.new": { argTypes: [DYN], result: DYN },
1124
+ "ffi.argument": { argTypes: [DYN, STRING], result: DYN },
1125
+ "ffi.memoryModule": { argTypes: [DYN], result: DYN },
1126
+ "intl.segmenterNew": { argTypes: [], result: DYN },
1127
+ "arrayBuffer.is": { argTypes: [DYN], result: BOOL },
1128
+ "arrayBuffer.isView": { argTypes: [DYN], result: BOOL },
1129
+ "arrayBuffer.byteLengthGetter": { argTypes: [], result: F64 },
1130
+ "arrayBuffer.byteLengthDescriptor": { argTypes: [DYN], result: DYN },
1131
+ "arrayBuffer.viewU8C": { argTypes: [DYN, DYN, DYN], result: bytesOf("u8c") },
1132
+ "arrayBuffer.viewI8": { argTypes: [DYN, DYN, DYN], result: bytesOf("i8") },
1133
+ "arrayBuffer.viewU16": { argTypes: [DYN, DYN, DYN], result: bytesOf("u16") },
1134
+ "arrayBuffer.viewI16": { argTypes: [DYN, DYN, DYN], result: bytesOf("i16") },
1135
+ "arrayBuffer.viewU8": { argTypes: [DYN, DYN, DYN], result: BYTES_U8 },
1136
+ "arrayBuffer.viewU32": { argTypes: [DYN, DYN, DYN], result: bytesOf("u32") },
1137
+ "arrayBuffer.viewI32": { argTypes: [DYN, DYN, DYN], result: bytesOf("i32") },
1138
+ "arrayBuffer.viewF32": { argTypes: [DYN, DYN, DYN], result: bytesOf("f32") },
1139
+ "arrayBuffer.viewF64": { argTypes: [DYN, DYN, DYN], result: bytesOf("f64") },
1140
+ "arrayBuffer.viewDV": { argTypes: [DYN, DYN, DYN], result: BYTES_U8 },
1047
1141
  "dyn.objKeys": { argTypes: [DYN], result: DYN },
1142
+ "dyn.forInKeys": { argTypes: [DYN], result: DYN },
1048
1143
  "dyn.hasOwn": { argTypes: [DYN, STRING], result: BOOL },
1144
+ "dyn.propertyIsEnumerable": { argTypes: [DYN, STRING], result: BOOL },
1049
1145
  "dyn.assign": { argTypes: [DYN, DYN], result: DYN },
1146
+ "dyn.copyDataProperties": { argTypes: [DYN, DYN], result: DYN },
1050
1147
  "dyn.packPush": { argTypes: [DYN, DYN], result: VOID },
1051
1148
  "dyn.packPushSpread": { argTypes: [DYN, DYN, STRING], result: VOID },
1052
1149
  "dyn.packPushSpreadIter": { argTypes: [DYN, DYN], result: VOID },
1053
1150
  "dyn.assignAll": { argTypes: [DYN, DYN], result: DYN },
1054
1151
  "dyn.objCreateNullProto": { argTypes: [], result: DYN },
1152
+ "dyn.arrayPrototype": { argTypes: [], result: DYN },
1153
+ "dyn.classPrototype": { argTypes: [DYN, DYN], result: DYN },
1154
+ "dyn.classBasePrototype": { argTypes: [DYN], result: DYN },
1155
+ "dyn.classSuper": { argTypes: [DYN, DYN, DYN], result: VOID },
1156
+ "dyn.assignPrototype": { argTypes: [DYN, DYN, DYN], result: DYN },
1157
+ "dyn.objCreate": { argTypes: [DYN], result: DYN },
1158
+ "dyn.objCreateWithProperties": { argTypes: [DYN, DYN], result: DYN },
1159
+ "dyn.getPrototype": { argTypes: [DYN], result: DYN },
1160
+ "dyn.setPrototype": { argTypes: [DYN, DYN], result: DYN },
1161
+ "dyn.getOwnPropertyNames": { argTypes: [DYN], result: DYN },
1162
+ "dyn.getOwnPropertySymbols": { argTypes: [DYN], result: DYN },
1163
+ "dyn.getOwnPropertyDescriptors": { argTypes: [DYN], result: DYN },
1164
+ "dyn.preventExtensions": { argTypes: [DYN], result: DYN },
1165
+ "dyn.isExtensible": { argTypes: [DYN], result: BOOL },
1166
+ "dyn.seal": { argTypes: [DYN], result: DYN },
1167
+ "dyn.isSealed": { argTypes: [DYN], result: BOOL },
1055
1168
  "dyn.objValues": { argTypes: [DYN], result: DYN },
1056
1169
  "dyn.objEntries": { argTypes: [DYN], result: DYN },
1057
1170
  "dyn.structuredClone": { argTypes: [DYN, DYN], result: DYN },
1058
1171
  "dyn.cloneMissing": { argTypes: [], result: DYN },
1059
1172
  "dyn.cloneTransferFail": { argTypes: [], result: DYN },
1060
1173
  "regex.new": { argTypes: [STRING, STRING], result: REGEX },
1174
+ "regex.newChecked": { argTypes: [DYN, DYN], result: REGEX },
1061
1175
  // node:events EventEmitter: receivers are emitter-hierarchy objects and
1062
1176
  // the chaining forms (on/off/removeAll/setMax) return the receiver's
1063
1177
  // own class — program-dependent object types, checked in the libCall
@@ -1082,6 +1196,7 @@ export const LIB_FN_SIGS = {
1082
1196
  "emitter.emitError": { argTypes: [null, STRING, null], result: BOOL },
1083
1197
  "emitter.count": { argTypes: [null, STRING], result: F64 },
1084
1198
  "emitter.countFn": { argTypes: [null, STRING, null], result: F64 },
1199
+ "emitter.countDyn": { argTypes: [null, STRING, DYN], result: F64 },
1085
1200
  "emitter.names": { argTypes: [null], result: VOID },
1086
1201
  "emitter.listeners": { argTypes: [null, STRING], result: VOID },
1087
1202
  "emitter.onData": { argTypes: [null, STRING, null, BOOL, BOOL], result: VOID },
@@ -1269,6 +1384,8 @@ export const LIB_FN_SIGS = {
1269
1384
  "dc.tcTraceSync": { argTypes: [F64, DYN, DYN, DYN, DYN], result: DYN },
1270
1385
  "dc.tcTraceCallback": { argTypes: [F64, DYN, F64, DYN, DYN, DYN], result: DYN },
1271
1386
  "dc.tcTracePromise": { argTypes: [F64, DYN, DYN, DYN, DYN], result: { kind: "promise", inner: DYN } },
1387
+ "process.onUncaughtException": { argTypes: [DYN, BOOL, BOOL], result: VOID },
1388
+ "process.offUncaughtException": { argTypes: [DYN, BOOL], result: VOID },
1272
1389
  "process.onUnhandledRejection": { argTypes: [DYN, BOOL], result: VOID },
1273
1390
  "process.offUnhandledRejection": { argTypes: [DYN], result: VOID },
1274
1391
  "process.onRejectionHandled": { argTypes: [DYN, BOOL], result: VOID },
@@ -1338,6 +1455,7 @@ export const LIB_FN_SIGS = {
1338
1455
  // Arg 0 is a packed f64[] OR a bytes value (the spread-typed-array
1339
1456
  // form) — checked in the libCall case.
1340
1457
  "string.fromCharCode": { argTypes: [null], result: STRING },
1458
+ "string.fromCodePoint": { argTypes: [null], result: STRING },
1341
1459
  "string.lastIndexOf": { argTypes: [STRING, STRING], result: F64 },
1342
1460
  "string.lastIndexOfFrom": { argTypes: [STRING, STRING, F64], result: F64 },
1343
1461
  "string.raw": { argTypes: [arrayOf(STRING), arrayOf(STRING)], result: STRING },
@@ -1386,6 +1504,30 @@ export function validateModule(mod) {
1386
1504
  }
1387
1505
  const retainedFfiCallbacks = new Map();
1388
1506
  for (const entry of mod.ffiImports ?? []) {
1507
+ if (entry.callbackOperation !== undefined) {
1508
+ const fail = (detail) => { errors.push({ message: `FFI callback operation "${entry.name}" ${detail}`, loc: moduleLoc }); };
1509
+ if (!entry.library || entry.library.includes("\0"))
1510
+ fail("requires a library name");
1511
+ if (entry.callbackOperation === "register") {
1512
+ const param = entry.params[0];
1513
+ if (entry.params.length !== 1 || !param || !isFfiCallbackParam(param) ||
1514
+ param.callback.id !== "callback" || param.callback.lifetime !== "retained" || param.callback.invoke !== "script-thread" ||
1515
+ param.callback.params.some(p => typeof p !== "string" || ["cstring", "string", "bytes"].includes(p)) ||
1516
+ entry.returns !== "pointer" || entry.callbackTarget !== undefined)
1517
+ fail("has an invalid registration ABI");
1518
+ }
1519
+ else if (entry.callbackOperation === "release") {
1520
+ const target = entry.callbackTarget ? ffiByName.get(entry.callbackTarget) : undefined;
1521
+ if (entry.params.length !== 0 || entry.returns !== "void" || target?.callbackOperation !== "register" ||
1522
+ target.library !== entry.library)
1523
+ fail("has an invalid release target or ABI");
1524
+ }
1525
+ else
1526
+ fail("has an invalid operation");
1527
+ }
1528
+ else if (entry.callbackTarget !== undefined) {
1529
+ errors.push({ message: `FFI binding "${entry.name}" has a callback target without a release operation`, loc: moduleLoc });
1530
+ }
1389
1531
  const ids = new Set();
1390
1532
  for (const param of entry.params) {
1391
1533
  if (!isFfiCallbackParam(param))
@@ -1398,6 +1540,9 @@ export function validateModule(mod) {
1398
1540
  errors.push({ message: `FFI callback "${entry.name}:${param.callback.id}" has invalid invoke mode`, loc: moduleLoc });
1399
1541
  }
1400
1542
  if (param.callback.invoke === "foreign") {
1543
+ if (param.callback.params.some((p) => p === "i64" || p === "u64" || p === "pointer")) {
1544
+ errors.push({ message: `FFI foreign callback "${entry.name}:${param.callback.id}" has unsupported 64-bit or pointer arguments`, loc: moduleLoc });
1545
+ }
1401
1546
  if (param.callback.lifetime !== "retained") {
1402
1547
  errors.push({ message: `FFI foreign callback "${entry.name}:${param.callback.id}" is not retained`, loc: moduleLoc });
1403
1548
  }
@@ -1535,6 +1680,30 @@ export function validateModule(mod) {
1535
1680
  errors.push({ message: `duplicate class "${cls.name}"`, loc: cls.loc });
1536
1681
  }
1537
1682
  classesByName.set(cls.name, cls);
1683
+ if (cls.localCaptures !== undefined && (cls.runtime || cls.genericOf !== undefined)) {
1684
+ errors.push({ message: `class ${cls.name}: local class cannot use a runtime or generic family layout`, loc: cls.loc });
1685
+ }
1686
+ if (cls.localCaptures !== undefined) {
1687
+ const environment = cls.fields.find((field) => field.name === `%classEnvironment:${cls.name}`);
1688
+ if (environment?.type.kind !== "classval" || environment.type.className !== cls.name) {
1689
+ errors.push({ message: `class ${cls.name}: local class requires its constructor environment field`, loc: cls.loc });
1690
+ }
1691
+ }
1692
+ if (cls.localBaseCapture !== undefined) {
1693
+ const base = cls.localCaptures?.[cls.localBaseCapture];
1694
+ if (!Number.isInteger(cls.localBaseCapture) || base?.type.kind !== "classval" || base.type.className !== cls.base) {
1695
+ errors.push({ message: `class ${cls.name}: invalid local base capture`, loc: cls.loc });
1696
+ }
1697
+ }
1698
+ if (cls.jsLength !== undefined && (!Number.isSafeInteger(cls.jsLength) || cls.jsLength < 0)) {
1699
+ errors.push({ message: `class ${cls.name}: invalid constructor length`, loc: cls.loc });
1700
+ }
1701
+ if (cls.prototypeDataHelper !== undefined) {
1702
+ const helper = functionsByName.get(cls.prototypeDataHelper);
1703
+ if (!helper || helper.params.length !== 0 || helper.returnType.kind !== "dyn" || helper.captures !== undefined || helper.classCaptures !== undefined) {
1704
+ errors.push({ message: `class ${cls.name}: prototype data helper must be a noncapturing () => dyn function`, loc: cls.loc });
1705
+ }
1706
+ }
1538
1707
  const seen = new Set();
1539
1708
  for (const f of cls.fields) {
1540
1709
  if (seen.has(f.name)) {
@@ -1577,6 +1746,9 @@ export function validateModule(mod) {
1577
1746
  errors.push({ message: `class ${cls.name}: undeclared base "${cls.base}"`, loc: cls.loc });
1578
1747
  continue;
1579
1748
  }
1749
+ if (base.localCaptures !== undefined && cls.localBaseCapture === undefined) {
1750
+ errors.push({ message: `class ${cls.name}: local base requires a captured constructor`, loc: cls.loc });
1751
+ }
1580
1752
  const seen = new Set([cls.name]);
1581
1753
  for (let c = base; c; c = c.base !== undefined ? classesByName.get(c.base) : undefined) {
1582
1754
  if (seen.has(c.name)) {
@@ -1651,9 +1823,16 @@ export function validateModule(mod) {
1651
1823
  // field count) — anything else has no honest index/JSON story.
1652
1824
  if (rec.tuple) {
1653
1825
  const names = new Set(rec.fields.map((f) => f.name));
1826
+ let positionsComplete = true;
1827
+ for (let i = 0; i < rec.fields.length; i++) {
1828
+ if (!names.has(String(i))) {
1829
+ positionsComplete = false;
1830
+ break;
1831
+ }
1832
+ }
1654
1833
  if (rec.fields.length === 0 ||
1655
1834
  names.size !== rec.fields.length ||
1656
- [...Array(rec.fields.length).keys()].some((i) => !names.has(String(i)))) {
1835
+ !positionsComplete) {
1657
1836
  errors.push({ message: `record ${rec.id}: tuple fields are not "0".."${rec.fields.length - 1}"`, loc: noLoc });
1658
1837
  }
1659
1838
  if (rec.indexValue) {
@@ -1675,31 +1854,64 @@ export function validateModule(mod) {
1675
1854
  errors.push({ message: `duplicate union "${u.id}"`, loc: noLoc });
1676
1855
  }
1677
1856
  unionsById.set(u.id, u);
1857
+ }
1858
+ for (const u of mod.unions ?? []) {
1678
1859
  if (u.arms.length < 2) {
1679
1860
  errors.push({ message: `union ${u.id}: fewer than 2 arms`, loc: noLoc });
1680
1861
  }
1862
+ if (u.discriminant) {
1863
+ const { field, cases } = u.discriminant;
1864
+ const tags = new Set();
1865
+ const values = new Set();
1866
+ for (const candidate of cases) {
1867
+ const arm = u.arms[candidate.tag];
1868
+ const record = arm?.kind === "record" ? recordsById.get(arm.shapeId) : undefined;
1869
+ const member = record?.fields.find((entry) => entry.name === field);
1870
+ if (!Number.isInteger(candidate.tag) || candidate.tag < 0 || !member || tags.has(candidate.tag)) {
1871
+ errors.push({ message: `union ${u.id}: invalid discriminant tag ${candidate.tag}`, loc: noLoc });
1872
+ }
1873
+ tags.add(candidate.tag);
1874
+ if (candidate.values.length === 0) {
1875
+ errors.push({ message: `union ${u.id}: empty discriminant values for tag ${candidate.tag}`, loc: noLoc });
1876
+ }
1877
+ for (const value of candidate.values) {
1878
+ if (value === undefined) {
1879
+ errors.push({ message: `union ${u.id}: undefined discriminant value`, loc: noLoc });
1880
+ continue;
1881
+ }
1882
+ const fieldTypes = member?.type.kind === "union"
1883
+ ? unionsById.get(member.type.unionId)?.arms ?? [] : member ? [member.type] : [];
1884
+ const valid = fieldTypes.some((type) => typeof value === "string" ? type.kind === "string"
1885
+ : typeof value === "boolean" ? type.kind === "bool"
1886
+ : typeof value === "number" && Number.isFinite(value) && type.kind === "f64");
1887
+ const key = typeof value + ":" + String(value);
1888
+ if (!valid || values.has(key)) {
1889
+ errors.push({ message: `union ${u.id}: invalid or repeated discriminant value ${key}`, loc: noLoc });
1890
+ }
1891
+ values.add(key);
1892
+ }
1893
+ }
1894
+ for (let tag = 0; tag < u.arms.length; tag++) {
1895
+ if (u.arms[tag].kind === "record" && !tags.has(tag)) {
1896
+ errors.push({ message: `union ${u.id}: missing discriminant for record arm ${tag}`, loc: noLoc });
1897
+ }
1898
+ }
1899
+ }
1681
1900
  u.arms.forEach((arm, i) => {
1682
1901
  // The unit kinds (undefinedT/nullT) are valid arms — union membership
1683
- // is the ONLY place they may appear; void/union/map/dyn/jsval/date
1684
- // stay out (maps and scalar Date values have no supported union
1685
- // representation/discriminant to narrow on). Func/set arm
1686
- // sibling rules live in unionFuncSetArmsOk (shared with the frontend's
1687
- // union builders): a func arm allows unit and FUNC siblings (the
1688
- // nullable-callback shape, and the primitive-constructor tables where
1689
- // closure pointer identity per tag is the narrowing); a set arm is
1690
- // valid exactly when every other arm is a unit (the defaulted-Set-
1691
- // param ABI); func/set-beside-data stays out.
1902
+ // is the ONLY place they may appear. Containers are valid beside
1903
+ // unit arms: tag tests distinguish absence while the reference
1904
+ // payload preserves identity. The shared rule refuses data siblings.
1692
1905
  if (arm.kind === "void" ||
1693
1906
  arm.kind === "union" ||
1694
- arm.kind === "map" ||
1695
1907
  arm.kind === "dyn" ||
1696
1908
  arm.kind === "jsval" ||
1697
1909
  arm.kind === "date" ||
1698
1910
  arm.kind === "generator") {
1699
1911
  errors.push({ message: `union ${u.id}: arm ${i} is ${arm.kind}`, loc: noLoc });
1700
1912
  }
1701
- if ((arm.kind === "func" || arm.kind === "set") &&
1702
- !unionFuncSetArmsOk(u.arms)) {
1913
+ if ((arm.kind === "map" || arm.kind === "set" || arm.kind === "promise") &&
1914
+ !unionContainerArmsOk(u.arms)) {
1703
1915
  errors.push({ message: `union ${u.id}: ${arm.kind} arm ${i} beside non-unit arms`, loc: noLoc });
1704
1916
  }
1705
1917
  if (arm.kind === "record" && !recordsById.has(arm.shapeId)) {
@@ -1791,6 +2003,9 @@ export function validateModule(mod) {
1791
2003
  }
1792
2004
  };
1793
2005
  for (const g of mod.globals ?? []) {
2006
+ if (g.tdz && g.type.kind !== "record" && g.type.kind !== "func" && g.type.kind !== "dyn") {
2007
+ errors.push({ message: `TDZ global "${g.name}" must have record, function, or checked-value storage`, loc: noLoc });
2008
+ }
1794
2009
  if (isUnitType(g.type)) {
1795
2010
  errors.push({ message: `global "${g.name}" has bare unit type ${g.type.kind}`, loc: noLoc });
1796
2011
  }
@@ -1890,6 +2105,8 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
1890
2105
  // Unit kinds live only inside unions: a bare-unit local, param, or
1891
2106
  // return type is frontend breakage (mapType never produces them).
1892
2107
  for (const l of fn.locals) {
2108
+ if (l.tdz && !l.boxed)
2109
+ err(`TDZ local "${l.name}" must be boxed`, fn.loc);
1893
2110
  if (isUnitType(l.type))
1894
2111
  err(`local "${l.name}" has bare unit type ${l.type.kind}`, fn.loc);
1895
2112
  }
@@ -1908,15 +2125,30 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
1908
2125
  if (p.type.kind === "caught")
1909
2126
  err(`param "${p.name}" is caught-typed`, fn.loc);
1910
2127
  }
1911
- for (const c of fn.captures ?? []) {
2128
+ for (const c of [...(fn.captures ?? []), ...(fn.classCaptures ?? [])]) {
1912
2129
  const local = locals.get(c.localId);
1913
2130
  if (!local)
1914
2131
  err(`capture "${c.name}" has no local entry "${c.localId}"`, fn.loc);
1915
2132
  else if (!local.boxed)
1916
2133
  err(`capture local "${c.localId}" is not boxed`, fn.loc);
2134
+ else if (!typeEquals(local.type, c.type))
2135
+ err(`capture local "${c.localId}" has the wrong type`, fn.loc);
1917
2136
  if (c.type.kind === "caught")
1918
2137
  err(`capture "${c.name}" is caught-typed`, fn.loc);
1919
2138
  }
2139
+ if (fn.classCaptures !== undefined) {
2140
+ const self = fn.params[0];
2141
+ const cls = self?.type.kind === "object" ? classes.get(self.type.className) : undefined;
2142
+ if (fn.captures !== undefined || cls?.localCaptures === undefined) {
2143
+ err("class captures require a local-class instance receiver and no closure environment", fn.loc);
2144
+ }
2145
+ for (const capture of fn.classCaptures) {
2146
+ const slot = cls?.localCaptures?.[capture.slot];
2147
+ if (!Number.isInteger(capture.slot) || !slot || !typeEquals(slot.type, capture.type)) {
2148
+ err(`class capture "${capture.name}" has an invalid slot or type`, fn.loc);
2149
+ }
2150
+ }
2151
+ }
1920
2152
  const expectType = (expr, want, what) => {
1921
2153
  if (!typeEquals(expr.type, want)) {
1922
2154
  // Same-kind mismatches (func vs func, record vs record) would be
@@ -1957,12 +2189,218 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
1957
2189
  seen.add(type.unionId);
1958
2190
  return unions.get(type.unionId)?.arms.some((arm) => liveDynRefEligible(arm, seen)) ?? false;
1959
2191
  };
2192
+ function checkNullishOperands(e) {
2193
+ expectType(e.right, e.type, "nullish right operand");
2194
+ // The ISLAND form: `a ?? b` over an engine value — left, right,
2195
+ // and result are all handles (the emitters' jsval nullish arm).
2196
+ if (e.left.type.kind === "jsval") {
2197
+ if (e.type.kind !== "jsval")
2198
+ err("jsval nullish must answer jsval", e.loc);
2199
+ return;
2200
+ }
2201
+ // The CHECKED-DYNAMIC form: the runtime kind decides (the
2202
+ // emitters' scr_dyn_is_nullish arm) — left, right, and result
2203
+ // all live in the checked-dynamic tree.
2204
+ if (e.left.type.kind === "dyn") {
2205
+ if (e.type.kind !== "dyn")
2206
+ err("dyn nullish must answer dyn", e.loc);
2207
+ return;
2208
+ }
2209
+ if (e.left.type.kind !== "union") {
2210
+ err(`nullish left must be a union, got ${e.left.type.kind}`, e.loc);
2211
+ return;
2212
+ }
2213
+ const def = unions.get(e.left.type.unionId);
2214
+ if (!def) {
2215
+ err(`nullish left references unknown union ${e.left.type.unionId}`, e.loc);
2216
+ return;
2217
+ }
2218
+ if (!def.arms.some(isUnitType)) {
2219
+ err("nullish left union has no unit arm (frontend must fence)", e.loc);
2220
+ }
2221
+ // Two shapes: pass-through (type === left's union) or narrowed
2222
+ // (type === the union's SINGLE non-unit arm).
2223
+ if (!typeEquals(e.type, e.left.type)) {
2224
+ const rest = def.arms.filter((a) => !isUnitType(a));
2225
+ if (rest.length !== 1 || !typeEquals(e.type, rest[0])) {
2226
+ err("nullish type must be the left union or its single non-unit arm", e.loc);
2227
+ }
2228
+ }
2229
+ }
2230
+ function checkBranchingTree(root) {
2231
+ // Predicates and conditional dispatch can nest in either direction.
2232
+ // Preserve child-before-parent diagnostics with bounded native stack
2233
+ // use, including trees that mix the three branching operators.
2234
+ const pending = [{ expr: root, visited: false }];
2235
+ while (pending.length !== 0) {
2236
+ const task = pending.pop();
2237
+ const e = task.expr;
2238
+ if (!task.visited) {
2239
+ if (e.kind === "logical" || e.kind === "nullish") {
2240
+ pending.push({ expr: e, visited: true });
2241
+ pending.push({ expr: e.right, visited: false });
2242
+ pending.push({ expr: e.left, visited: false });
2243
+ }
2244
+ else if (e.kind === "ternary") {
2245
+ pending.push({ expr: e, visited: true });
2246
+ pending.push({ expr: e.else_, visited: false });
2247
+ pending.push({ expr: e.then, visited: false });
2248
+ pending.push({ expr: e.cond, visited: false });
2249
+ }
2250
+ else {
2251
+ checkExpr(e);
2252
+ }
2253
+ continue;
2254
+ }
2255
+ if (e.kind === "logical") {
2256
+ if (e.type.kind !== "f64" && e.type.kind !== "string" && e.type.kind !== "bool" &&
2257
+ e.type.kind !== "jsval" && e.type.kind !== "union" && e.type.kind !== "dyn") {
2258
+ err(`logical ${e.op} must be f64|string|bool|jsval|union|dyn, got ${e.type.kind}`, e.loc);
2259
+ }
2260
+ if (e.type.kind === "union")
2261
+ checkTruthyUnion(e.type.unionId, e.loc);
2262
+ expectType(e.left, e.type, `logical ${e.op} left`);
2263
+ expectType(e.right, e.type, `logical ${e.op} right`);
2264
+ }
2265
+ else if (e.kind === "nullish") {
2266
+ checkNullishOperands(e);
2267
+ }
2268
+ else if (e.kind === "ternary") {
2269
+ expectType(e.cond, BOOL, "ternary condition");
2270
+ expectType(e.then, e.type, "ternary then-branch");
2271
+ expectType(e.else_, e.type, "ternary else-branch");
2272
+ if (e.type.kind === "void")
2273
+ err("ternary must not be void", e.loc);
2274
+ }
2275
+ }
2276
+ }
2277
+ // Keep expression families in separate functions so native bootstrap builds
2278
+ // do not feed LLVM a single control-flow graph containing every IR check.
1960
2279
  function checkExpr(e) {
2280
+ switch (e.kind) {
2281
+ case "numLit":
2282
+ case "strLit":
2283
+ case "moduleNsRef":
2284
+ case "boolLit":
2285
+ case "unitLit":
2286
+ case "varRef":
2287
+ case "bin":
2288
+ case "unary":
2289
+ case "incDec":
2290
+ case "fieldIncDec":
2291
+ case "assignExpr":
2292
+ case "seqExpr":
2293
+ case "dynDestrCheck":
2294
+ case "dynIterN":
2295
+ case "toBool":
2296
+ case "logical":
2297
+ case "nullish":
2298
+ case "ternary":
2299
+ case "unionEq":
2300
+ case "unionFuncEq":
2301
+ return checkScalarExpr(e);
2302
+ case "strConcat":
2303
+ case "strEq":
2304
+ case "strCmp":
2305
+ case "optChain":
2306
+ case "chainRecv":
2307
+ case "orDefault":
2308
+ case "toString":
2309
+ case "strIntrinsic":
2310
+ case "regexLit":
2311
+ case "templateStrings":
2312
+ case "regexIntrinsic":
2313
+ return checkStringExpr(e);
2314
+ case "arrayLit":
2315
+ case "arrayNewLen":
2316
+ case "arrayGet":
2317
+ case "arrayHas":
2318
+ case "arrayState":
2319
+ case "bytesNew":
2320
+ case "bytesIntrinsic":
2321
+ case "arrIntrinsic":
2322
+ return checkArrayExpr(e);
2323
+ case "mapNew":
2324
+ case "mapIntrinsic":
2325
+ case "setNew":
2326
+ case "setIntrinsic":
2327
+ return checkCollectionExpr(e);
2328
+ case "call":
2329
+ case "ffiCall":
2330
+ case "closure":
2331
+ case "callValue":
2332
+ return checkCallExpr(e);
2333
+ case "selfRef":
2334
+ case "new":
2335
+ case "fieldGet":
2336
+ case "promiseVoidWiden":
2337
+ case "upcast":
2338
+ case "downcast":
2339
+ case "classRef":
2340
+ case "newValue":
2341
+ case "instanceOfValue":
2342
+ case "instanceOf":
2343
+ case "virtualCall":
2344
+ return checkClassExpr(e);
2345
+ case "recordLit":
2346
+ case "recordClone":
2347
+ case "recordGet":
2348
+ case "recordKeyGet":
2349
+ case "recordOvfHas":
2350
+ case "recordOvfKeys":
2351
+ return checkRecordExpr(e);
2352
+ case "dynFrom":
2353
+ case "dynFromJsval":
2354
+ case "dynCall":
2355
+ case "dynInvoke":
2356
+ case "dynObjLit":
2357
+ case "dynArrLit":
2358
+ case "unionWrap":
2359
+ case "dynTest":
2360
+ case "dynKeyGet":
2361
+ case "dynHasKey":
2362
+ case "dynScalarEq":
2363
+ case "caughtTest":
2364
+ case "caughtCheck":
2365
+ case "caughtToDyn":
2366
+ case "caughtNarrow":
2367
+ return checkDynamicExpr(e);
2368
+ case "unionNarrow":
2369
+ case "unionDisc":
2370
+ case "unionKeyGet":
2371
+ case "unionIsTag":
2372
+ return checkUnionExpr(e);
2373
+ case "intrinsic":
2374
+ return checkIntrinsicExpr(e);
2375
+ case "libCall":
2376
+ return checkLibCall(e);
2377
+ case "jsonStringify":
2378
+ case "dynCheck":
2379
+ return checkConversionExpr(e);
2380
+ case "awaitExpr":
2381
+ case "yieldExpr":
2382
+ case "genResume":
2383
+ case "awaitUnionExpr":
2384
+ case "newPromise":
2385
+ case "promiseWithResolvers":
2386
+ return checkAsyncExpr(e);
2387
+ case "jsMarshal":
2388
+ case "jsOp":
2389
+ case "jsExit":
2390
+ case "jsBridgePromise":
2391
+ return checkIslandExpr(e);
2392
+ default: {
2393
+ const _exhaustive = e;
2394
+ void _exhaustive;
2395
+ }
2396
+ }
2397
+ }
2398
+ function checkScalarExpr(e) {
1961
2399
  switch (e.kind) {
1962
2400
  case "numLit":
1963
2401
  // ±Infinity and NaN are real literals (the globals
1964
- // `Infinity`/`NaN`, Number constants) — both backends spell them
1965
- // (INFINITY/NAN macros in C, bit-encoded f64 in LLVM).
2402
+ // `Infinity`/`NaN`, Number constants) — the backend spells them
2403
+ // (bit-encoded f64 in LLVM).
1966
2404
  // procStream is the ONE non-f64 numLit: process.stdout/stderr as
1967
2405
  // first-class values mint the stream's fd (1/2) as the scalar —
1968
2406
  // the prefixStream idiom.
@@ -2026,6 +2464,8 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
2026
2464
  (e.left.type.kind === "array" ||
2027
2465
  e.left.type.kind === "map" ||
2028
2466
  e.left.type.kind === "set" ||
2467
+ e.left.type.kind === "regex" ||
2468
+ e.left.type.kind === "url" ||
2029
2469
  e.left.type.kind === "object" ||
2030
2470
  e.left.type.kind === "record" ||
2031
2471
  // Symbol identity IS pointer identity (the frontend's rule).
@@ -2129,12 +2569,20 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
2129
2569
  // Statements in an expression cannot jump out of the expression,
2130
2570
  // but a local state branch is valid: optional array stores must
2131
2571
  // choose ARRAY_VALUE versus ARRAY_UNDEFINED before the final result
2132
- // is evaluated. Nested blocks/ifs are checked recursively below.
2133
- const allowed = new Set(["varDecl", "assign", "exprStmt", "fieldSet", "recordSet", "recordKeySet", "arraySet", "arraySetLength", "arraySetUndefined", "arrayDelete", "bytesSet", "block", "if"]);
2572
+ // is evaluated. Delegation also needs a local loop. Nested control
2573
+ // flow is checked recursively; jumps still cannot leave the region.
2574
+ const allowed = new Set(["varDecl", "assign", "exprStmt", "fieldSet", "recordSet", "recordKeySet", "arraySet", "arraySetLength", "arraySetUndefined", "arrayDelete", "bytesSet", "block", "if", "while"]);
2575
+ if (e.generatorDelegate) {
2576
+ if (!fn.generator || fn.async)
2577
+ err("delegation sequence outside a synchronous generator", e.loc);
2578
+ allowed.add("return");
2579
+ allowed.add("throw");
2580
+ allowed.add("runtimeFence");
2581
+ }
2134
2582
  const flat = (ss) => {
2135
2583
  for (const s of ss) {
2136
2584
  if (!allowed.has(s.kind)) {
2137
- err(`seqExpr statement kind "${s.kind}" is not straight-line`, s.loc);
2585
+ err(`seqExpr statement kind "${s.kind}" can leave the expression`, s.loc);
2138
2586
  continue;
2139
2587
  }
2140
2588
  if (s.kind === "block") {
@@ -2148,6 +2596,12 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
2148
2596
  checkExpr(s.cond);
2149
2597
  continue;
2150
2598
  }
2599
+ if (s.kind === "while") {
2600
+ expectType(s.cond, BOOL, "seqExpr while condition");
2601
+ checkExpr(s.cond);
2602
+ flat(s.body);
2603
+ continue;
2604
+ }
2151
2605
  checkStmt(s);
2152
2606
  }
2153
2607
  };
@@ -2190,16 +2644,9 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
2190
2644
  err("toBool must be bool", e.loc);
2191
2645
  break;
2192
2646
  case "logical":
2193
- checkExpr(e.left);
2194
- checkExpr(e.right);
2195
- if (e.type.kind !== "f64" && e.type.kind !== "string" && e.type.kind !== "bool" &&
2196
- e.type.kind !== "jsval" && e.type.kind !== "union" && e.type.kind !== "dyn") {
2197
- err(`logical ${e.op} must be f64|string|bool|jsval|union|dyn, got ${e.type.kind}`, e.loc);
2198
- }
2199
- if (e.type.kind === "union")
2200
- checkTruthyUnion(e.type.unionId, e.loc);
2201
- expectType(e.left, e.type, `logical ${e.op} left`);
2202
- expectType(e.right, e.type, `logical ${e.op} right`);
2647
+ case "nullish":
2648
+ case "ternary":
2649
+ checkBranchingTree(e);
2203
2650
  break;
2204
2651
  case "unionEq": {
2205
2652
  checkExpr(e.left);
@@ -2233,6 +2680,14 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
2233
2680
  err("unionFuncEq must be bool", e.loc);
2234
2681
  break;
2235
2682
  }
2683
+ default: {
2684
+ const _exhaustive = e;
2685
+ void _exhaustive;
2686
+ }
2687
+ }
2688
+ }
2689
+ function checkStringExpr(e) {
2690
+ switch (e.kind) {
2236
2691
  case "strConcat":
2237
2692
  checkExpr(e.left);
2238
2693
  checkExpr(e.right);
@@ -2250,16 +2705,6 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
2250
2705
  if (e.type.kind !== "bool")
2251
2706
  err(`${e.kind} must be bool`, e.loc);
2252
2707
  break;
2253
- case "ternary":
2254
- checkExpr(e.cond);
2255
- checkExpr(e.then);
2256
- checkExpr(e.else_);
2257
- expectType(e.cond, BOOL, "ternary condition");
2258
- expectType(e.then, e.type, "ternary then-branch");
2259
- expectType(e.else_, e.type, "ternary else-branch");
2260
- if (e.type.kind === "void")
2261
- err("ternary must not be void", e.loc);
2262
- break;
2263
2708
  case "optChain": {
2264
2709
  checkExpr(e.receiver);
2265
2710
  // An island-handle chain (`x?.y` on 'any'): the nullish test is a
@@ -2312,13 +2757,13 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
2312
2757
  break;
2313
2758
  }
2314
2759
  const rest = def.arms.filter((a) => !isUnitType(a));
2315
- if (rest.length !== 1 || rest.length === def.arms.length) {
2316
- err("optChain receiver must have unit arms and exactly one non-unit arm", e.loc);
2760
+ if (rest.length === 0 || rest.length === def.arms.length) {
2761
+ err("optChain receiver must have unit arms and at least one non-unit arm", e.loc);
2317
2762
  break;
2318
2763
  }
2319
2764
  if (activeChains.has(e.id))
2320
2765
  err(`optChain id "${e.id}" shadows an active chain`, e.loc);
2321
- activeChains.set(e.id, rest[0]);
2766
+ activeChains.set(e.id, rest.length === 1 ? rest[0] : e.receiver.type);
2322
2767
  checkExpr(e.body);
2323
2768
  activeChains.delete(e.id);
2324
2769
  if (e.type.kind === "void") {
@@ -2347,47 +2792,6 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
2347
2792
  expectType(e, bound, "chainRecv");
2348
2793
  break;
2349
2794
  }
2350
- case "nullish": {
2351
- checkExpr(e.left);
2352
- checkExpr(e.right);
2353
- expectType(e.right, e.type, "nullish right operand");
2354
- // The ISLAND form: `a ?? b` over an engine value — left, right,
2355
- // and result are all handles (the emitters' jsval nullish arm).
2356
- if (e.left.type.kind === "jsval") {
2357
- if (e.type.kind !== "jsval")
2358
- err("jsval nullish must answer jsval", e.loc);
2359
- break;
2360
- }
2361
- // The CHECKED-DYNAMIC form: the runtime kind decides (the
2362
- // emitters' scr_dyn_is_nullish arm) — left, right, and result
2363
- // all live in the checked-dynamic tree.
2364
- if (e.left.type.kind === "dyn") {
2365
- if (e.type.kind !== "dyn")
2366
- err("dyn nullish must answer dyn", e.loc);
2367
- break;
2368
- }
2369
- if (e.left.type.kind !== "union") {
2370
- err(`nullish left must be a union, got ${e.left.type.kind}`, e.loc);
2371
- break;
2372
- }
2373
- const def = unions.get(e.left.type.unionId);
2374
- if (!def) {
2375
- err(`nullish left references unknown union ${e.left.type.unionId}`, e.loc);
2376
- break;
2377
- }
2378
- if (!def.arms.some(isUnitType)) {
2379
- err("nullish left union has no unit arm (frontend must fence)", e.loc);
2380
- }
2381
- // Two shapes: pass-through (type === left's union) or narrowed
2382
- // (type === the union's SINGLE non-unit arm).
2383
- if (!typeEquals(e.type, e.left.type)) {
2384
- const rest = def.arms.filter((a) => !isUnitType(a));
2385
- if (rest.length !== 1 || !typeEquals(e.type, rest[0])) {
2386
- err("nullish type must be the left union or its single non-unit arm", e.loc);
2387
- }
2388
- }
2389
- break;
2390
- }
2391
2795
  case "orDefault": {
2392
2796
  checkExpr(e.left);
2393
2797
  checkExpr(e.right);
@@ -2521,6 +2925,14 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
2521
2925
  }
2522
2926
  break;
2523
2927
  }
2928
+ default: {
2929
+ const _exhaustive = e;
2930
+ void _exhaustive;
2931
+ }
2932
+ }
2933
+ }
2934
+ function checkArrayExpr(e) {
2935
+ switch (e.kind) {
2524
2936
  case "arrayLit": {
2525
2937
  if (e.type.kind !== "array") {
2526
2938
  err(`arrayLit must be array-typed, got ${e.type.kind}`, e.loc);
@@ -2602,21 +3014,17 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
2602
3014
  if (e.source) {
2603
3015
  checkExpr(e.source);
2604
3016
  const sk = e.source.type;
2605
- if (sk.kind === "bytes") {
2606
- // Same-elem copies only (cross-kind construction is fenced).
2607
- if (!typeEquals(sk, e.type)) {
2608
- err(`bytesNew copy source elem mismatch`, e.loc);
2609
- }
2610
- }
2611
- else if (sk.kind === "array") {
3017
+ if (sk.kind === "array") {
2612
3018
  if (sk.elem.kind !== "f64") {
2613
3019
  err(`bytesNew array source must hold f64, got ${sk.elem.kind}`, e.loc);
2614
3020
  }
2615
3021
  }
2616
- else if (sk.kind !== "f64") {
3022
+ else if (sk.kind !== "f64" && sk.kind !== "bytes" && sk.kind !== "dyn") {
2617
3023
  err(`bytesNew source of kind ${sk.kind}`, e.loc);
2618
3024
  }
2619
3025
  }
3026
+ if (e.from && e.source?.type.kind !== "dyn")
3027
+ err("bytesNew from requires a dyn source", e.loc);
2620
3028
  break;
2621
3029
  }
2622
3030
  case "bytesIntrinsic": {
@@ -2652,6 +3060,9 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
2652
3060
  err(`bytesIntrinsic ${e.method} args[1] must be a strLit encoding`, e.loc);
2653
3061
  }
2654
3062
  const EXTRA_SIGS = {
3063
+ buffer: { argTypes: [], minArgs: 0, result: DYN },
3064
+ setFromDyn: { argTypes: [DYN, F64], minArgs: 1, result: VOID },
3065
+ copyWithin: { argTypes: [F64, F64, F64], minArgs: 3, result: bytesOf(recv.elem) },
2655
3066
  equals: { argTypes: [BYTES_U8], minArgs: 1, result: BOOL },
2656
3067
  compareBuf: { argTypes: [BYTES_U8, F64, F64, F64, F64], minArgs: 1, result: F64 },
2657
3068
  // [needle, align, byteOffset?] — an OMITTED byteOffset is Node's
@@ -2691,7 +3102,7 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
2691
3102
  : e.method === "toArray"
2692
3103
  ? { argTypes: [], minArgs: 0, result: arrayOf(F64) }
2693
3104
  : e.method === "setFrom"
2694
- ? { argTypes: [bytesOf(recv.elem), F64], minArgs: 1, result: VOID }
3105
+ ? { argTypes: [e.args[0]?.type.kind === "bytes" ? e.args[0].type : bytesOf(recv.elem), F64], minArgs: 1, result: VOID }
2695
3106
  : e.method === "toString" || e.method === "toStringVar"
2696
3107
  ? { argTypes: [STRING, F64, F64], minArgs: 1, result: STRING }
2697
3108
  : e.method === "readNum"
@@ -2803,7 +3214,7 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
2803
3214
  // misjudge JS ===; the frontend fences these.
2804
3215
  err(`arrIntrinsic ${e.method} on union elements (frontend must reject)`, e.loc);
2805
3216
  }
2806
- if (e.method === "shift" || e.method === "pop") {
3217
+ if ((e.method === "shift" || e.method === "pop") && !(elem.kind === "dyn" && e.type.kind === "dyn")) {
2807
3218
  const rdef = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
2808
3219
  if (!rdef ||
2809
3220
  !rdef.arms.some((arm) => arm.kind === "undefinedT") ||
@@ -2829,12 +3240,20 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
2829
3240
  }
2830
3241
  break;
2831
3242
  }
3243
+ default: {
3244
+ const _exhaustive = e;
3245
+ void _exhaustive;
3246
+ }
3247
+ }
3248
+ }
3249
+ function checkCollectionExpr(e) {
3250
+ switch (e.kind) {
2832
3251
  case "mapNew": {
2833
3252
  if (e.type.kind !== "map") {
2834
3253
  err(`mapNew must be map-typed, got ${e.type.kind}`, e.loc);
2835
3254
  break;
2836
3255
  }
2837
- if (!isSupportedMapKey(e.type.key)) {
3256
+ if (!isSupportedMapKey(e.type.key, e.type.key.kind === "union" ? unions.get(e.type.key.unionId)?.arms : undefined)) {
2838
3257
  err(`mapNew key kind ${e.type.key.kind} (frontend must fence)`, e.loc);
2839
3258
  }
2840
3259
  if (!isSupportedMapValue(e.type.value)) {
@@ -2868,6 +3287,10 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
2868
3287
  }
2869
3288
  checkExpr(e.args[0]);
2870
3289
  expectType(e.args[0], key, "mapIntrinsic get key");
3290
+ if (value.kind === "dyn") {
3291
+ expectType(e, DYN, "mapIntrinsic get result");
3292
+ break;
3293
+ }
2871
3294
  const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
2872
3295
  const rest = def ? def.arms.filter((a) => a.kind !== "undefinedT") : [];
2873
3296
  // When V is itself a union its own undefined arm (if any) folds
@@ -2917,7 +3340,7 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
2917
3340
  err(`setNew must be set-typed, got ${e.type.kind}`, e.loc);
2918
3341
  break;
2919
3342
  }
2920
- if (!isSupportedSetElem(e.type.elem)) {
3343
+ if (!isSupportedSetElem(e.type.elem, e.type.elem.kind === "union" ? unions.get(e.type.elem.unionId)?.arms : undefined)) {
2921
3344
  err(`setNew element kind ${e.type.elem.kind} (frontend must fence)`, e.loc);
2922
3345
  }
2923
3346
  // The seed is one T[]-typed expression (T = the element type).
@@ -2961,6 +3384,14 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
2961
3384
  }
2962
3385
  break;
2963
3386
  }
3387
+ default: {
3388
+ const _exhaustive = e;
3389
+ void _exhaustive;
3390
+ }
3391
+ }
3392
+ }
3393
+ function checkCallExpr(e) {
3394
+ switch (e.kind) {
2964
3395
  case "call": {
2965
3396
  for (const a of e.args)
2966
3397
  checkExpr(a);
@@ -3060,6 +3491,10 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
3060
3491
  }
3061
3492
  case "callValue": {
3062
3493
  checkExpr(e.callee);
3494
+ if (e.receiver !== undefined) {
3495
+ checkExpr(e.receiver);
3496
+ expectType(e.receiver, DYN, "callValue receiver");
3497
+ }
3063
3498
  for (const a of e.args)
3064
3499
  checkExpr(a);
3065
3500
  if (e.callee.type.kind !== "func") {
@@ -3080,6 +3515,14 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
3080
3515
  }
3081
3516
  break;
3082
3517
  }
3518
+ default: {
3519
+ const _exhaustive = e;
3520
+ void _exhaustive;
3521
+ }
3522
+ }
3523
+ }
3524
+ function checkClassExpr(e) {
3525
+ switch (e.kind) {
3083
3526
  case "selfRef":
3084
3527
  if (fn.captures === undefined) {
3085
3528
  err("selfRef outside a lifted function", e.loc);
@@ -3096,6 +3539,8 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
3096
3539
  break;
3097
3540
  }
3098
3541
  const ctor = functions.get(`%${e.className}.constructor`);
3542
+ if (cls.localCaptures !== undefined)
3543
+ err(`new ${e.className}: local class requires a class value`, e.loc);
3099
3544
  if (!ctor) {
3100
3545
  err(`new ${e.className}: missing constructor function`, e.loc);
3101
3546
  break;
@@ -3205,6 +3650,17 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
3205
3650
  if (!typeEquals(e.type, { kind: "classval", className: e.className })) {
3206
3651
  err(`classRef to "${e.className}" must have that classval type`, e.loc);
3207
3652
  }
3653
+ if ((e.captures === undefined) !== (cls.localCaptures === undefined) ||
3654
+ (e.captures?.length ?? 0) !== (cls.localCaptures?.length ?? 0)) {
3655
+ err(`classRef to "${e.className}" must supply its class captures`, e.loc);
3656
+ }
3657
+ (e.captures ?? []).forEach((id, index) => {
3658
+ const local = locals.get(id);
3659
+ const wanted = cls.localCaptures?.[index];
3660
+ if (!local?.boxed || (wanted && !typeEquals(local.type, wanted.type))) {
3661
+ err(`classRef capture "${id}" must name a box with the declared type`, e.loc);
3662
+ }
3663
+ });
3208
3664
  break;
3209
3665
  }
3210
3666
  case "newValue": {
@@ -3248,6 +3704,9 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
3248
3704
  // Both sides must be hierarchy members: the operand needs a vt
3249
3705
  // word to read; a standalone target class has one possible value
3250
3706
  // and the frontend folds it statically.
3707
+ if (classes.get(e.classValue.type.className)?.localCaptures !== undefined &&
3708
+ e.value.type.kind === "object" && classes.get(e.value.type.className)?.localCaptures !== undefined)
3709
+ break;
3251
3710
  if (!hierarchy.has(e.classValue.type.className)) {
3252
3711
  err(`instanceOfValue against standalone class "${e.classValue.type.className}"`, e.loc);
3253
3712
  }
@@ -3325,6 +3784,14 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
3325
3784
  }
3326
3785
  break;
3327
3786
  }
3787
+ default: {
3788
+ const _exhaustive = e;
3789
+ void _exhaustive;
3790
+ }
3791
+ }
3792
+ }
3793
+ function checkRecordExpr(e) {
3794
+ switch (e.kind) {
3328
3795
  case "recordLit": {
3329
3796
  if (e.type.kind !== "record") {
3330
3797
  err(`recordLit must be record-typed, got ${e.type.kind}`, e.loc);
@@ -3444,8 +3911,12 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
3444
3911
  // literal key naming no declared field) skip the declared check
3445
3912
  // and require the overflow to exist.
3446
3913
  const surfaces = (t) => typeEquals(t, e.type) ||
3447
- (e.type.kind === "union" &&
3448
- (unions.get(e.type.unionId)?.arms.some((a) => typeEquals(a, t)) ?? false)) ||
3914
+ (e.type.kind === "union" && (() => {
3915
+ const result = unions.get(e.type.unionId);
3916
+ const source = t.kind === "union" ? unions.get(t.unionId) : undefined;
3917
+ return !!result && (result.arms.some((a) => typeEquals(a, t)) ||
3918
+ (!!source && unionWideningTags(source.arms, result.arms) !== null));
3919
+ })()) ||
3449
3920
  e.type.kind === "dyn";
3450
3921
  if (e.overflowOnly && !shape.indexValue) {
3451
3922
  err(`recordKeyGet on ${e.shapeId}: overflowOnly read of a shape without an index signature`, e.loc);
@@ -3461,6 +3932,20 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
3461
3932
  }
3462
3933
  break;
3463
3934
  }
3935
+ case "recordOvfHas": {
3936
+ checkExpr(e.obj);
3937
+ checkExpr(e.key);
3938
+ const shape = records.get(e.shapeId);
3939
+ if (!shape)
3940
+ err(`recordOvfHas on undeclared shape "${e.shapeId}"`, e.loc);
3941
+ else if (!shape.indexValue || shape.tuple)
3942
+ err(`recordOvfHas on ${e.shapeId}: requires an index-signature record`, e.loc);
3943
+ expectType(e.obj, { kind: "record", shapeId: e.shapeId }, "recordOvfHas receiver");
3944
+ expectType(e.key, STRING, "recordOvfHas key");
3945
+ if (e.type.kind !== "bool")
3946
+ err("recordOvfHas must be bool", e.loc);
3947
+ break;
3948
+ }
3464
3949
  case "recordOvfKeys": {
3465
3950
  checkExpr(e.obj);
3466
3951
  const shape = records.get(e.shapeId);
@@ -3476,6 +3961,14 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
3476
3961
  }
3477
3962
  break;
3478
3963
  }
3964
+ default: {
3965
+ const _exhaustive = e;
3966
+ void _exhaustive;
3967
+ }
3968
+ }
3969
+ }
3970
+ function checkDynamicExpr(e) {
3971
+ switch (e.kind) {
3479
3972
  case "dynFrom": {
3480
3973
  if (e.type.kind !== "dyn")
3481
3974
  err(`dynFrom must be dyn-typed, got ${e.type.kind}`, e.loc);
@@ -3517,6 +4010,10 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
3517
4010
  }
3518
4011
  case "dynCall": {
3519
4012
  checkExpr(e.callee);
4013
+ if (e.receiver !== undefined) {
4014
+ checkExpr(e.receiver);
4015
+ expectType(e.receiver, DYN, "dynCall receiver");
4016
+ }
3520
4017
  expectType(e.callee, DYN, "dynCall callee");
3521
4018
  if (e.type.kind !== "dyn")
3522
4019
  err(`dynCall must be dyn-typed, got ${e.type.kind}`, e.loc);
@@ -3559,8 +4056,8 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
3559
4056
  err(`dynObjLit must be dyn-typed, got ${e.type.kind}`, e.loc);
3560
4057
  for (const f of e.fields ?? []) {
3561
4058
  checkExpr(f.key);
3562
- if (f.key.type.kind !== "string")
3563
- err(`dynObjLit key of kind ${f.key.type.kind} (must be string)`, e.loc);
4059
+ if (f.key.type.kind !== "string" && f.key.type.kind !== "dyn")
4060
+ err(`dynObjLit key of kind ${f.key.type.kind} (must be string or dyn)`, e.loc);
3564
4061
  checkExpr(f.value);
3565
4062
  if (f.value.type.kind !== "dyn")
3566
4063
  err(`dynObjLit field value of kind ${f.value.type.kind} (must be dyn)`, e.loc);
@@ -3622,14 +4119,17 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
3622
4119
  expectType(e.value, { kind: "dyn" }, "dynTest operand");
3623
4120
  if (e.type.kind !== "bool")
3624
4121
  err("dynTest must be bool", e.loc);
4122
+ if (e.bytesElem !== undefined && (e.test !== "bytes" || !Object.hasOwn(BYTES_ELEMENT_NAME, e.bytesElem))) {
4123
+ err("dynTest bytesElem requires a valid bytes test", e.loc);
4124
+ }
3625
4125
  break;
3626
4126
  }
3627
4127
  case "dynKeyGet": {
3628
4128
  checkExpr(e.value);
3629
4129
  checkExpr(e.key);
3630
4130
  expectType(e.value, { kind: "dyn" }, "dynKeyGet operand");
3631
- if (e.key.type.kind !== "string")
3632
- err(`dynKeyGet key is ${e.key.type.kind}, not string`, e.loc);
4131
+ if (e.key.type.kind !== "string" && e.key.type.kind !== "dyn")
4132
+ err(`dynKeyGet key is ${e.key.type.kind}, not string or dyn`, e.loc);
3633
4133
  if (e.type.kind !== "dyn")
3634
4134
  err("dynKeyGet must be dyn", e.loc);
3635
4135
  break;
@@ -3704,6 +4204,14 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
3704
4204
  }
3705
4205
  break;
3706
4206
  }
4207
+ default: {
4208
+ const _exhaustive = e;
4209
+ void _exhaustive;
4210
+ }
4211
+ }
4212
+ }
4213
+ function checkUnionExpr(e) {
4214
+ switch (e.kind) {
3707
4215
  case "unionNarrow": {
3708
4216
  checkExpr(e.value);
3709
4217
  const def = unions.get(e.unionId);
@@ -3777,7 +4285,11 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
3777
4285
  // non-unit arms have no keyed read at all. Number keys read ARRAY
3778
4286
  // arms; string keys read RECORD arms.
3779
4287
  const resultUnion = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
3780
- const surfaces = (t) => typeEquals(t, e.type) || !!resultUnion?.arms.some((a) => typeEquals(a, t));
4288
+ const surfaces = (t) => typeEquals(t, e.type) || !!resultUnion?.arms.some((a) => typeEquals(a, t)) ||
4289
+ (t.kind === "union" && !!resultUnion && (() => {
4290
+ const source = unions.get(t.unionId);
4291
+ return !!source && unionWideningTags(source.arms, resultUnion.arms) !== null;
4292
+ })());
3781
4293
  def.arms.forEach((arm, i) => {
3782
4294
  if (arm.kind === "undefinedT" || arm.kind === "nullT") {
3783
4295
  if (!resultUnion?.arms.some((a) => a.kind === "undefinedT")) {
@@ -3832,1296 +4344,1346 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
3832
4344
  err("unionIsTag must be bool", e.loc);
3833
4345
  break;
3834
4346
  }
3835
- case "intrinsic":
3836
- if (e.name === "module.await") {
3837
- if (e.args.length !== 1)
3838
- err("module.await takes exactly one argument", e.loc);
3839
- for (const a of e.args) {
3840
- checkExpr(a);
3841
- if (a.type.kind !== "promise" || a.type.inner.kind !== "void") {
3842
- err(`${typeKey(a.type)} argument to module.await (needs promise<void>)`, a.loc);
3843
- }
3844
- }
3845
- if (e.type.kind !== "void")
3846
- err("module.await must be void", e.loc);
3847
- break;
3848
- }
3849
- if (e.name === "promise.all") {
3850
- // ONE argument: an array of promises whose inner type is the
3851
- // result's array element (or void, collapsing to promise<void>).
3852
- // The exact-inner-type rule is the frontend's fence; the coarse
3853
- // shape keeps hand-written IR honest.
3854
- if (e.args.length !== 1)
3855
- err("promise.all takes exactly one argument", e.loc);
3856
- for (const a of e.args) {
3857
- checkExpr(a);
3858
- if (a.type.kind !== "array" || a.type.elem.kind !== "promise") {
3859
- err(`${a.type.kind} argument to promise.all (needs an array of promises)`, a.loc);
3860
- }
3861
- }
3862
- if (e.type.kind !== "promise")
3863
- err("promise.all must be promise-typed", e.loc);
3864
- else if (e.type.inner.kind !== "array" && e.type.inner.kind !== "void") {
3865
- err("promise.all result must be a promise of an array (or void)", e.loc);
3866
- }
3867
- break;
3868
- }
3869
- if (e.name === "promise.reject") {
3870
- // ONE argument: the %Error-rooted reason object (the rejection
3871
- // payload shares the thrown-Error representation — the
3872
- // frontend's fence pins the hierarchy; the coarse object shape
3873
- // keeps hand-written IR honest) or a checked-dynamic reason
3874
- // (the thrown-dyn representation — identity flows to catch and
3875
- // unhandledRejection observers). The result is the
3876
- // context-named promise.
3877
- if (e.args.length !== 1)
3878
- err("promise.reject takes exactly one argument", e.loc);
3879
- for (const a of e.args) {
3880
- checkExpr(a);
3881
- if (a.type.kind !== "object" && a.type.kind !== "dyn") {
3882
- err(`${a.type.kind} argument to promise.reject (needs an Error object or a dyn reason)`, a.loc);
3883
- }
3884
- }
3885
- if (e.type.kind !== "promise")
3886
- err("promise.reject must be promise-typed", e.loc);
3887
- break;
3888
- }
3889
- if (e.name === "promise.resolve") {
3890
- // Zero args (Promise<void>) or one plain value of the result's
3891
- // inner type — promise arguments never reach the intrinsic
3892
- // (the frontend returns them as-is).
3893
- if (e.args.length > 1)
3894
- err("promise.resolve takes at most one argument", e.loc);
3895
- for (const a of e.args) {
3896
- checkExpr(a);
3897
- if (a.type.kind === "promise") {
3898
- err("promise argument to promise.resolve (identity belongs in the frontend)", a.loc);
3899
- }
3900
- }
3901
- if (e.type.kind !== "promise")
3902
- err("promise.resolve must be promise-typed", e.loc);
3903
- else if (e.args.length === 0 && e.type.inner.kind !== "void") {
3904
- err("zero-argument promise.resolve must be promise<void>", e.loc);
3905
- }
3906
- else if (e.args.length === 1 && !typeEquals(e.args[0].type, e.type.inner)) {
3907
- err("promise.resolve argument must be the result's inner type", e.loc);
3908
- }
3909
- break;
3910
- }
3911
- if (e.name === "promise.race") {
3912
- // Entries are promises; the result is the combined promise. The
3913
- // per-entry inner-type compatibility (equal to the result inner,
3914
- // one of its union arms, or a sub-union of it) is the frontend's
3915
- // fence; here the coarse shape keeps hand-written IR honest.
3916
- if (e.args.length === 0)
3917
- err("promise.race with no entries", e.loc);
3918
- for (const a of e.args) {
3919
- checkExpr(a);
3920
- if (a.type.kind !== "promise") {
3921
- err(`${a.type.kind} entry in promise.race`, a.loc);
3922
- }
3923
- }
3924
- if (e.type.kind !== "promise")
3925
- err("promise.race must be promise-typed", e.loc);
3926
- break;
3927
- }
3928
- for (const a of e.args) {
3929
- checkExpr(a);
3930
- // Arrays/functions/records/unions stay out of console.log (and
3931
- // its stderr twin console.error) by design (the ambient signature
3932
- // accepts number|string|boolean; a union of those satisfies it,
3933
- // so the frontend rejects union args explicitly) — inspect
3934
- // formatting is unimplemented, so the backend must never see one.
3935
- if (a.type.kind !== "f64" && a.type.kind !== "string" && a.type.kind !== "bool") {
3936
- err(`${a.type.kind} argument to ${e.name}`, a.loc);
3937
- }
3938
- }
3939
- if (e.type.kind !== "void")
3940
- err(`${e.name} must be void`, e.loc);
3941
- break;
3942
- case "libCall": {
3943
- const sig = LIB_FN_SIGS[e.fn];
3944
- if (!sig) {
3945
- err(`libCall of unknown library function "${e.fn}"`, e.loc);
3946
- break;
3947
- }
3948
- // emitter.emit is variadic: (recv, name) plus the event's tuple.
3949
- // The stream constructors (trailing option callbacks), write/end
3950
- // (the optional chunk/cb tail), and unpipe (the optional
3951
- // destination) admit a longer list the same way.
3952
- const variadic = e.fn === "emitter.emit" || e.fn === "emitter.emitFlex" ||
3953
- e.fn === "readable.new" || e.fn === "writable.new" ||
3954
- e.fn === "duplex.new" || e.fn === "transform.new" ||
3955
- e.fn === "passthrough.new" ||
3956
- e.fn === "readable.init" || e.fn === "writable.init" ||
3957
- e.fn === "duplex.init" || e.fn === "transform.init" ||
3958
- e.fn === "passthrough.init" ||
3959
- e.fn === "readable.initDyn" || e.fn === "writable.initDyn" ||
3960
- e.fn === "duplex.initDyn" || e.fn === "transform.initDyn" ||
3961
- e.fn === "passthrough.initDyn" ||
3962
- e.fn === "stream.pipeline" || e.fn === "stream.pipelineDyn" ||
3963
- e.fn === "sp.pipeline" ||
3964
- e.fn === "writable.write" ||
3965
- e.fn === "writable.writeStr" || e.fn === "writable.writeU" ||
3966
- e.fn === "writable.end" ||
3967
- e.fn === "readable.unpipe";
3968
- if (variadic
3969
- ? e.args.length < sig.argTypes.length
3970
- : e.args.length !== sig.argTypes.length) {
3971
- err(`libCall ${e.fn}: ${e.args.length} args, expected ${sig.argTypes.length}`, e.loc);
3972
- }
3973
- e.args.forEach((a, i) => {
3974
- checkExpr(a);
3975
- const want = sig.argTypes[i];
3976
- if (want)
3977
- expectType(a, want, `libCall ${e.fn} arg ${i}`);
3978
- });
3979
- if (e.fn === "fileHandle.read" || e.fn === "fileHandle.writeBytes" || e.fn === "fileHandle.writeStr") {
3980
- const inner = e.type.kind === "promise" ? e.type.inner : undefined;
3981
- const shape = inner?.kind === "record" ? records.get(inner.shapeId) : undefined;
3982
- const countName = e.fn === "fileHandle.read" ? "bytesRead" : "bytesWritten";
3983
- const payload = e.args[1]?.type;
3984
- const count = shape?.fields.find((f) => f.name === countName);
3985
- const buffer = shape?.fields.find((f) => f.name === "buffer");
3986
- const ok = shape !== undefined && !shape.tuple && shape.indexValue === undefined && shape.fields.length === 2 &&
3987
- count?.type.kind === "f64" && payload !== undefined && buffer !== undefined &&
3988
- typeEquals(buffer.type, payload);
3989
- if (!ok) {
3990
- err(`libCall ${e.fn} must return a promise of { ${countName}: number, buffer }`, e.loc);
3991
- }
3992
- break;
3993
- }
3994
- if (e.fn === "fetch.streamFrom") {
3995
- const t = e.args[0]?.type;
3996
- const ok = t?.kind === "string" ||
3997
- (t?.kind === "bytes" && t.elem === "u8") ||
3998
- (t?.kind === "array" &&
3999
- canConvertToDyn(t.elem, (id) => records.get(id), (id) => unions.get(id))) ||
4000
- t?.kind === "dyn";
4001
- if (!ok) {
4002
- err(`libCall fetch.streamFrom arg 0: expected a supported iterable, got ${t?.kind}`, e.loc);
4003
- }
4004
- break;
4005
- }
4006
- if (e.fn === "fetch.readerRead") {
4007
- if (e.type.kind !== "promise" || e.type.inner.kind !== "record") {
4008
- err(`libCall fetch.readerRead must return a promise of a read-result record`, e.loc);
4009
- }
4010
- break;
4011
- }
4012
- if (e.fn === "fetch.responseText" || e.fn === "fetch.responseBytes") {
4013
- const valueType = e.fn === "fetch.responseText" ? STRING : BYTES_U8;
4014
- const inner = e.type.kind === "promise" ? e.type.inner : null;
4015
- const union = inner?.kind === "union" ? unions.get(inner.unionId) : undefined;
4016
- if (inner === null ||
4017
- (!typeEquals(inner, valueType) &&
4018
- !union?.arms.some((arm) => typeEquals(arm, valueType)))) {
4019
- err(`libCall ${e.fn} must return a promise whose value includes ${valueType.kind}`, e.loc);
4020
- }
4021
- break;
4022
- }
4023
- if (e.fn === "string.fromCharCode") {
4024
- // One packed f64[] or one bytes value (the spread form).
4025
- const t = e.args[0]?.type;
4026
- const ok = t && ((t.kind === "array" && t.elem.kind === "f64") || t.kind === "bytes");
4027
- if (!ok) {
4028
- err(`libCall string.fromCharCode arg 0: expected number[] or bytes, got ${t?.kind}`, e.loc);
4029
- }
4030
- break;
4031
- }
4032
- if (e.fn === "process.envGet") {
4033
- // Result is the module's interned `string | undefined` union.
4034
- const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4035
- const ok = def &&
4036
- def.arms.length === 2 &&
4037
- def.arms[0].kind === "string" &&
4038
- def.arms[1].kind === "undefinedT";
4039
- if (!ok) {
4040
- err(`libCall process.envGet must return the 'string | undefined' union`, e.loc);
4041
- }
4042
- break;
4043
- }
4044
- if (e.fn === "process.columns" || e.fn === "process.rows") {
4045
- // Result is the module's interned `number | undefined` union.
4046
- const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4047
- const ok = def &&
4048
- def.arms.length === 2 &&
4049
- def.arms[0].kind === "f64" &&
4050
- def.arms[1].kind === "undefinedT";
4051
- if (!ok) {
4052
- err(`libCall ${e.fn} must return the 'number | undefined' union`, e.loc);
4053
- }
4054
- break;
4055
- }
4056
- if (e.fn === "http.createServer" || e.fn === "http2.createServerReq") {
4057
- // The request handler: void, at most (req, res) in order.
4058
- const cbT = e.args[0]?.type;
4059
- let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= 2;
4060
- if (ok && cbT?.kind === "func") {
4061
- const [p0, p1] = cbT.params;
4062
- if (p0 !== undefined && p0.kind !== "httpReq")
4063
- ok = false;
4064
- if (p1 !== undefined && p1.kind !== "httpRes")
4065
- ok = false;
4066
- }
4067
- if (!ok) {
4068
- err(`libCall ${e.fn} handler shape (frontend must fence)`, e.loc);
4069
- }
4070
- break;
4071
- }
4072
- if (e.fn === "http.serverOnRequest") {
4073
- // The 'request' listener: the same shape as http.createServer's
4074
- // handler — void, at most (req, res) in order.
4075
- const cbT = e.args[1]?.type;
4076
- let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= 2;
4077
- if (ok && cbT?.kind === "func") {
4078
- const [p0, p1] = cbT.params;
4079
- if (p0 !== undefined && p0.kind !== "httpReq")
4080
- ok = false;
4081
- if (p1 !== undefined && p1.kind !== "httpRes")
4082
- ok = false;
4083
- }
4084
- if (!ok) {
4085
- err(`libCall http.serverOnRequest handler shape (frontend must fence)`, e.loc);
4086
- }
4087
- break;
4088
- }
4089
- if (e.fn === "http2.serverOnSessionError") {
4090
- const cbT = e.args[1]?.type;
4091
- const ok = cbT?.kind === "func" && cbT.ret.kind === "void" &&
4092
- cbT.params.length <= 2 &&
4093
- (cbT.params[0] === undefined ||
4094
- (cbT.params[0].kind === "object" && cbT.params[0].className === "%Error")) &&
4095
- (cbT.params[1] === undefined || cbT.params[1].kind === "http2Session");
4096
- if (!ok) {
4097
- err(`libCall http2.serverOnSessionError callback shape (frontend must fence)`, e.loc);
4098
- }
4099
- break;
4100
- }
4101
- if (e.fn === "http.reqOnData") {
4102
- const cbT = e.args[1]?.type;
4103
- let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= 1;
4104
- if (ok && cbT?.kind === "func" && cbT.params.length === 1) {
4105
- const p = cbT.params[0];
4106
- // dyn = the checked-dynamic listener's adapter (the chunk
4107
- // boxes Buffer-flavored in the runtime data thunk).
4108
- ok = (p.kind === "bytes" && p.elem === "u8") || p.kind === "dyn";
4109
- }
4110
- if (!ok) {
4111
- err(`libCall http.reqOnData callback shape (frontend must fence)`, e.loc);
4112
- }
4113
- break;
4114
- }
4115
- if (e.fn === "http.reqStatusCode") {
4116
- // Result is the module's interned `number | undefined` union.
4117
- const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4118
- const ok = def &&
4119
- def.arms.length === 2 &&
4120
- def.arms[0].kind === "f64" &&
4121
- def.arms[1].kind === "undefinedT";
4122
- if (!ok) {
4123
- err(`libCall http.reqStatusCode must return the 'number | undefined' union`, e.loc);
4124
- }
4125
- break;
4126
- }
4127
- if (e.fn === "net.sockRemoteAddress") {
4128
- // Result is the interned `string | undefined` union (envGet's).
4129
- const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4130
- const ok = def &&
4131
- def.arms.length === 2 &&
4132
- def.arms[0].kind === "string" &&
4133
- def.arms[1].kind === "undefinedT";
4134
- if (!ok) {
4135
- err(`libCall net.sockRemoteAddress must return the 'string | undefined' union`, e.loc);
4136
- }
4137
- break;
4138
- }
4139
- if (e.fn === "net.sockEncrypted") {
4140
- // Result is the interned `boolean | undefined` union.
4141
- const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4142
- const ok = def &&
4143
- def.arms.length === 2 &&
4144
- def.arms[0].kind === "bool" &&
4145
- def.arms[1].kind === "undefinedT";
4146
- if (!ok) {
4147
- err(`libCall net.sockEncrypted must return the 'boolean | undefined' union`, e.loc);
4148
- }
4149
- break;
4150
- }
4151
- if (e.fn === "tls.sockAuthError") {
4152
- // Result is the interned `string | null` union (Node's
4153
- // authorizationError: the verify-failure code string, or null).
4154
- const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4155
- const ok = def &&
4156
- def.arms.length === 2 &&
4157
- def.arms[0].kind === "string" &&
4158
- def.arms[1].kind === "nullT";
4159
- if (!ok) {
4160
- err(`libCall tls.sockAuthError must return the 'string | null' union`, e.loc);
4161
- }
4162
- break;
4163
- }
4164
- if (e.fn === "http.requestCb" || e.fn === "https.requestCb" ||
4165
- e.fn === "http.requestUrlCb" || e.fn === "http.clientOnResponse" ||
4166
- e.fn === "http.requestAgentCb" || e.fn === "https.requestAgentCb" ||
4167
- e.fn === "https.requestUrlCb") {
4168
- // The response listener: void, no params or exactly (res: httpReq).
4169
- const cbT = e.args[e.fn === "http.requestCb" ? 7
4170
- : e.fn === "https.requestCb" ? 9
4171
- : e.fn === "http.requestUrlCb" || e.fn === "https.requestUrlCb" ? 3
4172
- : e.fn === "http.requestAgentCb" ? 8
4173
- : e.fn === "https.requestAgentCb" ? 10
4174
- : 1]?.type;
4175
- let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= 1;
4176
- if (ok && cbT?.kind === "func" && cbT.params.length === 1) {
4177
- ok = cbT.params[0].kind === "httpReq";
4178
- }
4179
- if (!ok) {
4180
- err(`libCall ${e.fn} callback shape (frontend must fence)`, e.loc);
4181
- }
4182
- break;
4183
- }
4184
- if (e.fn === "http.reqOnError" || e.fn === "http.clientOnError") {
4185
- // The error listener: void, no params or exactly (err: %Error).
4186
- const cbT = e.args[1]?.type;
4187
- let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= 1;
4188
- if (ok && cbT?.kind === "func" && cbT.params.length === 1) {
4189
- const p = cbT.params[0];
4190
- ok = p.kind === "object" && p.className === "%Error";
4191
- }
4192
- if (!ok) {
4193
- err(`libCall ${e.fn} callback shape (frontend must fence)`, e.loc);
4194
- }
4195
- break;
4196
- }
4197
- if (e.fn === "net.sockRead") {
4198
- // Result is the interned `Buffer | null` union.
4199
- const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4200
- const ok = def &&
4201
- def.arms.length === 2 &&
4202
- def.arms.some((a) => a.kind === "bytes" && a.elem === "u8") &&
4203
- def.arms.some((a) => a.kind === "nullT");
4204
- if (!ok) {
4205
- err(`libCall net.sockRead must return the 'Buffer | null' union`, e.loc);
4206
- }
4207
- break;
4208
- }
4209
- if (e.fn === "http.serverOnUpgrade" || e.fn === "http.clientOnUpgrade" ||
4210
- e.fn === "http.serverOnConnect") {
4211
- // (req, socket, head) or any shorter prefix, void return. The
4212
- // 'connect' registration additionally admits a socket slot
4213
- // that is a UNION carrying a netSocket arm (the h2 compat
4214
- // listener — the emitted adapter wraps the socket there).
4215
- const cbT = e.args[1]?.type;
4216
- let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= 3;
4217
- if (ok && cbT?.kind === "func") {
4218
- const [p0, p1, p2] = cbT.params;
4219
- if (p0 !== undefined && p0.kind !== "httpReq")
4220
- ok = false;
4221
- if (p1 !== undefined && p1.kind !== "netSocket") {
4222
- if (e.fn === "http.serverOnConnect" && p1?.kind === "union") {
4223
- const def = unions.get(p1.unionId);
4224
- if (!def || !def.arms.some((a) => a.kind === "netSocket"))
4225
- ok = false;
4226
- }
4227
- else {
4228
- ok = false;
4229
- }
4230
- }
4231
- if (p2 !== undefined && !(p2.kind === "bytes" && p2.elem === "u8"))
4347
+ default: {
4348
+ const _exhaustive = e;
4349
+ void _exhaustive;
4350
+ }
4351
+ }
4352
+ }
4353
+ function checkIntrinsicExpr(e) {
4354
+ if (e.name === "module.await") {
4355
+ if (e.args.length !== 1)
4356
+ err("module.await takes exactly one argument", e.loc);
4357
+ for (const a of e.args) {
4358
+ checkExpr(a);
4359
+ if (a.type.kind !== "promise" || a.type.inner.kind !== "void") {
4360
+ err(`${typeKey(a.type)} argument to module.await (needs promise<void>)`, a.loc);
4361
+ }
4362
+ }
4363
+ if (e.type.kind !== "void")
4364
+ err("module.await must be void", e.loc);
4365
+ return;
4366
+ }
4367
+ if (e.name === "promise.all") {
4368
+ // ONE argument: an array of promises whose inner type is the
4369
+ // result's array element (or void, collapsing to promise<void>).
4370
+ // The exact-inner-type rule is the frontend's fence; the coarse
4371
+ // shape keeps hand-written IR honest.
4372
+ if (e.args.length !== 1)
4373
+ err("promise.all takes exactly one argument", e.loc);
4374
+ for (const a of e.args) {
4375
+ checkExpr(a);
4376
+ if (a.type.kind !== "array" || a.type.elem.kind !== "promise") {
4377
+ err(`${a.type.kind} argument to promise.all (needs an array of promises)`, a.loc);
4378
+ }
4379
+ }
4380
+ if (e.type.kind !== "promise")
4381
+ err("promise.all must be promise-typed", e.loc);
4382
+ else if (e.type.inner.kind !== "array" && e.type.inner.kind !== "void") {
4383
+ err("promise.all result must be a promise of an array (or void)", e.loc);
4384
+ }
4385
+ return;
4386
+ }
4387
+ if (e.name === "promise.reject") {
4388
+ // ONE argument: the %Error-rooted reason object (the rejection
4389
+ // payload shares the thrown-Error representation — the
4390
+ // frontend's fence pins the hierarchy; the coarse object shape
4391
+ // keeps hand-written IR honest) or a checked-dynamic reason
4392
+ // (the thrown-dyn representation — identity flows to catch and
4393
+ // unhandledRejection observers). The result is the
4394
+ // context-named promise.
4395
+ if (e.args.length !== 1)
4396
+ err("promise.reject takes exactly one argument", e.loc);
4397
+ for (const a of e.args) {
4398
+ checkExpr(a);
4399
+ if (a.type.kind !== "object" && a.type.kind !== "dyn") {
4400
+ err(`${a.type.kind} argument to promise.reject (needs an Error object or a dyn reason)`, a.loc);
4401
+ }
4402
+ }
4403
+ if (e.type.kind !== "promise")
4404
+ err("promise.reject must be promise-typed", e.loc);
4405
+ return;
4406
+ }
4407
+ if (e.name === "promise.resolve") {
4408
+ // Zero args (Promise<void>) or one plain value of the result's
4409
+ // inner type — promise arguments never reach the intrinsic
4410
+ // (the frontend returns them as-is).
4411
+ if (e.args.length > 1)
4412
+ err("promise.resolve takes at most one argument", e.loc);
4413
+ for (const a of e.args) {
4414
+ checkExpr(a);
4415
+ if (a.type.kind === "promise") {
4416
+ err("promise argument to promise.resolve (identity belongs in the frontend)", a.loc);
4417
+ }
4418
+ }
4419
+ if (e.type.kind !== "promise")
4420
+ err("promise.resolve must be promise-typed", e.loc);
4421
+ else if (e.args.length === 0 && e.type.inner.kind !== "void") {
4422
+ err("zero-argument promise.resolve must be promise<void>", e.loc);
4423
+ }
4424
+ else if (e.args.length === 1 && !typeEquals(e.args[0].type, e.type.inner)) {
4425
+ err("promise.resolve argument must be the result's inner type", e.loc);
4426
+ }
4427
+ return;
4428
+ }
4429
+ if (e.name === "promise.race") {
4430
+ // Entries are promises; the result is the combined promise. The
4431
+ // per-entry inner-type compatibility (equal to the result inner,
4432
+ // one of its union arms, or a sub-union of it) is the frontend's
4433
+ // fence; here the coarse shape keeps hand-written IR honest.
4434
+ if (e.args.length === 0)
4435
+ err("promise.race with no entries", e.loc);
4436
+ for (const a of e.args) {
4437
+ checkExpr(a);
4438
+ if (a.type.kind !== "promise") {
4439
+ err(`${a.type.kind} entry in promise.race`, a.loc);
4440
+ }
4441
+ }
4442
+ if (e.type.kind !== "promise")
4443
+ err("promise.race must be promise-typed", e.loc);
4444
+ return;
4445
+ }
4446
+ for (const a of e.args) {
4447
+ checkExpr(a);
4448
+ // Arrays/functions/records/unions stay out of console.log (and
4449
+ // its stderr twin console.error) by design (the ambient signature
4450
+ // accepts number|string|boolean; a union of those satisfies it,
4451
+ // so the frontend rejects union args explicitly) — inspect
4452
+ // formatting is unimplemented, so the backend must never see one.
4453
+ if (a.type.kind !== "f64" && a.type.kind !== "string" && a.type.kind !== "bool") {
4454
+ err(`${a.type.kind} argument to ${e.name}`, a.loc);
4455
+ }
4456
+ }
4457
+ if (e.type.kind !== "void")
4458
+ err(`${e.name} must be void`, e.loc);
4459
+ }
4460
+ function checkLibCall(e) {
4461
+ const sig = LIB_FN_SIGS[e.fn];
4462
+ if (!sig) {
4463
+ err(`libCall of unknown library function "${e.fn}"`, e.loc);
4464
+ return;
4465
+ }
4466
+ // emitter.emit is variadic: (recv, name) plus the event's tuple.
4467
+ // The stream constructors (trailing option callbacks), write/end
4468
+ // (the optional chunk/cb tail), and unpipe (the optional
4469
+ // destination) admit a longer list the same way.
4470
+ const variadic = e.fn === "emitter.emit" || e.fn === "emitter.emitFlex" ||
4471
+ e.fn === "readable.new" || e.fn === "writable.new" ||
4472
+ e.fn === "duplex.new" || e.fn === "transform.new" ||
4473
+ e.fn === "passthrough.new" ||
4474
+ e.fn === "readable.init" || e.fn === "writable.init" ||
4475
+ e.fn === "duplex.init" || e.fn === "transform.init" ||
4476
+ e.fn === "passthrough.init" ||
4477
+ e.fn === "readable.initDyn" || e.fn === "writable.initDyn" ||
4478
+ e.fn === "duplex.initDyn" || e.fn === "transform.initDyn" ||
4479
+ e.fn === "passthrough.initDyn" ||
4480
+ e.fn === "stream.pipeline" || e.fn === "stream.pipelineDyn" ||
4481
+ e.fn === "sp.pipeline" ||
4482
+ e.fn === "writable.write" ||
4483
+ e.fn === "writable.writeStr" || e.fn === "writable.writeU" ||
4484
+ e.fn === "writable.end" ||
4485
+ e.fn === "readable.unpipe";
4486
+ if (variadic
4487
+ ? e.args.length < sig.argTypes.length
4488
+ : e.args.length !== sig.argTypes.length) {
4489
+ err(`libCall ${e.fn}: ${e.args.length} args, expected ${sig.argTypes.length}`, e.loc);
4490
+ }
4491
+ e.args.forEach((a, i) => {
4492
+ checkExpr(a);
4493
+ const want = sig.argTypes[i];
4494
+ if (want)
4495
+ expectType(a, want, `libCall ${e.fn} arg ${i}`);
4496
+ });
4497
+ if (checkLibValueCall(e))
4498
+ return;
4499
+ if (checkLibNetworkCall(e))
4500
+ return;
4501
+ if (checkLibFileCall(e))
4502
+ return;
4503
+ if (checkLibProcessCall(e))
4504
+ return;
4505
+ if (checkLibSpecialCall(e))
4506
+ return;
4507
+ if (checkLibStreamCall(e, sig.argTypes.length, sig.result))
4508
+ return;
4509
+ if (checkLibEmitterCall(e, sig.result))
4510
+ return;
4511
+ if (e.fn === "error.stack" || e.fn === "error.cause" || e.fn === "error.hasCause" || e.fn === "error.setCause" || e.fn === "error.deleteCause") {
4512
+ const recv = e.args[0];
4513
+ let cls = recv?.type.kind === "object" ? classes.get(recv.type.className) : undefined;
4514
+ while (cls?.base)
4515
+ cls = classes.get(cls.base);
4516
+ if (cls?.name !== "%Error")
4517
+ err(`libCall ${e.fn} receiver must be an error object`, e.loc);
4518
+ }
4519
+ if (e.fn === "error.ctor" || e.fn === "error.ctorOptions" || e.fn === "error.toString") {
4520
+ const recv = e.args[0];
4521
+ const wantErrorRoot = e.fn === "error.toString";
4522
+ const ok = recv &&
4523
+ isBuiltinErrorObject(recv.type) &&
4524
+ (!wantErrorRoot || (recv.type.kind === "object" && recv.type.className === "%Error"));
4525
+ if (!ok) {
4526
+ err(`libCall ${e.fn} receiver must be ${wantErrorRoot ? "'%Error'" : "a builtin error class"}`, e.loc);
4527
+ }
4528
+ }
4529
+ if (!typeEquals(e.type, sig.result)) {
4530
+ err(`libCall ${e.fn} must be ${sig.result.kind}, got ${e.type.kind}`, e.loc);
4531
+ }
4532
+ }
4533
+ function checkLibValueCall(e) {
4534
+ if (e.fn === "fileHandle.read" || e.fn === "fileHandle.writeBytes" || e.fn === "fileHandle.writeStr") {
4535
+ const inner = e.type.kind === "promise" ? e.type.inner : undefined;
4536
+ const shape = inner?.kind === "record" ? records.get(inner.shapeId) : undefined;
4537
+ const countName = e.fn === "fileHandle.read" ? "bytesRead" : "bytesWritten";
4538
+ const payload = e.args[1]?.type;
4539
+ const count = shape?.fields.find((f) => f.name === countName);
4540
+ const buffer = shape?.fields.find((f) => f.name === "buffer");
4541
+ const ok = shape !== undefined && !shape.tuple && shape.indexValue === undefined && shape.fields.length === 2 &&
4542
+ count?.type.kind === "f64" && payload !== undefined && buffer !== undefined &&
4543
+ typeEquals(buffer.type, payload);
4544
+ if (!ok) {
4545
+ err(`libCall ${e.fn} must return a promise of { ${countName}: number, buffer }`, e.loc);
4546
+ }
4547
+ return true;
4548
+ }
4549
+ if (e.fn === "fetch.streamFrom") {
4550
+ const t = e.args[0]?.type;
4551
+ const ok = t?.kind === "string" ||
4552
+ (t?.kind === "bytes" && t.elem === "u8") ||
4553
+ (t?.kind === "array" &&
4554
+ canConvertToDyn(t.elem, (id) => records.get(id), (id) => unions.get(id))) ||
4555
+ t?.kind === "dyn";
4556
+ if (!ok) {
4557
+ err(`libCall fetch.streamFrom arg 0: expected a supported iterable, got ${t?.kind}`, e.loc);
4558
+ }
4559
+ return true;
4560
+ }
4561
+ if (e.fn === "fetch.readerRead") {
4562
+ if (e.type.kind !== "promise" || e.type.inner.kind !== "record") {
4563
+ err(`libCall fetch.readerRead must return a promise of a read-result record`, e.loc);
4564
+ }
4565
+ return true;
4566
+ }
4567
+ if (e.fn === "fetch.responseText" || e.fn === "fetch.responseBytes") {
4568
+ const valueType = e.fn === "fetch.responseText" ? STRING : BYTES_U8;
4569
+ const inner = e.type.kind === "promise" ? e.type.inner : null;
4570
+ const union = inner?.kind === "union" ? unions.get(inner.unionId) : undefined;
4571
+ if (inner === null ||
4572
+ (!typeEquals(inner, valueType) &&
4573
+ !union?.arms.some((arm) => typeEquals(arm, valueType)))) {
4574
+ err(`libCall ${e.fn} must return a promise whose value includes ${valueType.kind}`, e.loc);
4575
+ }
4576
+ return true;
4577
+ }
4578
+ if (e.fn === "string.fromCharCode" || e.fn === "string.fromCodePoint") {
4579
+ // One packed f64[] or one bytes value (the spread form).
4580
+ const t = e.args[0]?.type;
4581
+ const ok = t && ((t.kind === "array" && t.elem.kind === "f64") || t.kind === "bytes");
4582
+ if (!ok) {
4583
+ err(`libCall ${e.fn} arg 0: expected number[] or bytes, got ${t?.kind}`, e.loc);
4584
+ }
4585
+ return true;
4586
+ }
4587
+ if (e.fn === "process.envGet") {
4588
+ // Result is the module's interned `string | undefined` union.
4589
+ const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4590
+ const ok = def &&
4591
+ def.arms.length === 2 &&
4592
+ def.arms[0].kind === "string" &&
4593
+ def.arms[1].kind === "undefinedT";
4594
+ if (!ok) {
4595
+ err(`libCall process.envGet must return the 'string | undefined' union`, e.loc);
4596
+ }
4597
+ return true;
4598
+ }
4599
+ if (e.fn === "process.columns" || e.fn === "process.rows") {
4600
+ // Result is the module's interned `number | undefined` union.
4601
+ const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4602
+ const ok = def &&
4603
+ def.arms.length === 2 &&
4604
+ def.arms[0].kind === "f64" &&
4605
+ def.arms[1].kind === "undefinedT";
4606
+ if (!ok) {
4607
+ err(`libCall ${e.fn} must return the 'number | undefined' union`, e.loc);
4608
+ }
4609
+ return true;
4610
+ }
4611
+ return false;
4612
+ }
4613
+ function checkLibNetworkCall(e) {
4614
+ if (e.fn === "http.createServer" || e.fn === "http2.createServerReq") {
4615
+ // The request handler: void, at most (req, res) in order.
4616
+ const cbT = e.args[0]?.type;
4617
+ let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= 2;
4618
+ if (ok && cbT?.kind === "func") {
4619
+ const [p0, p1] = cbT.params;
4620
+ if (p0 !== undefined && p0.kind !== "httpReq")
4621
+ ok = false;
4622
+ if (p1 !== undefined && p1.kind !== "httpRes")
4623
+ ok = false;
4624
+ }
4625
+ if (!ok) {
4626
+ err(`libCall ${e.fn} handler shape (frontend must fence)`, e.loc);
4627
+ }
4628
+ return true;
4629
+ }
4630
+ if (e.fn === "http.serverOnRequest") {
4631
+ // The 'request' listener: the same shape as http.createServer's
4632
+ // handler — void, at most (req, res) in order.
4633
+ const cbT = e.args[1]?.type;
4634
+ let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= 2;
4635
+ if (ok && cbT?.kind === "func") {
4636
+ const [p0, p1] = cbT.params;
4637
+ if (p0 !== undefined && p0.kind !== "httpReq")
4638
+ ok = false;
4639
+ if (p1 !== undefined && p1.kind !== "httpRes")
4640
+ ok = false;
4641
+ }
4642
+ if (!ok) {
4643
+ err(`libCall http.serverOnRequest handler shape (frontend must fence)`, e.loc);
4644
+ }
4645
+ return true;
4646
+ }
4647
+ if (e.fn === "http2.serverOnSessionError") {
4648
+ const cbT = e.args[1]?.type;
4649
+ const ok = cbT?.kind === "func" && cbT.ret.kind === "void" &&
4650
+ cbT.params.length <= 2 &&
4651
+ (cbT.params[0] === undefined ||
4652
+ (cbT.params[0].kind === "object" && cbT.params[0].className === "%Error")) &&
4653
+ (cbT.params[1] === undefined || cbT.params[1].kind === "http2Session");
4654
+ if (!ok) {
4655
+ err(`libCall http2.serverOnSessionError callback shape (frontend must fence)`, e.loc);
4656
+ }
4657
+ return true;
4658
+ }
4659
+ if (e.fn === "http.reqOnData") {
4660
+ const cbT = e.args[1]?.type;
4661
+ let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= 1;
4662
+ if (ok && cbT?.kind === "func" && cbT.params.length === 1) {
4663
+ const p = cbT.params[0];
4664
+ // dyn = the checked-dynamic listener's adapter (the chunk
4665
+ // boxes Buffer-flavored in the runtime data thunk).
4666
+ ok = (p.kind === "bytes" && p.elem === "u8") || p.kind === "dyn";
4667
+ }
4668
+ if (!ok) {
4669
+ err(`libCall http.reqOnData callback shape (frontend must fence)`, e.loc);
4670
+ }
4671
+ return true;
4672
+ }
4673
+ if (e.fn === "http.reqStatusCode") {
4674
+ // Result is the module's interned `number | undefined` union.
4675
+ const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4676
+ const ok = def &&
4677
+ def.arms.length === 2 &&
4678
+ def.arms[0].kind === "f64" &&
4679
+ def.arms[1].kind === "undefinedT";
4680
+ if (!ok) {
4681
+ err(`libCall http.reqStatusCode must return the 'number | undefined' union`, e.loc);
4682
+ }
4683
+ return true;
4684
+ }
4685
+ if (e.fn === "net.sockRemoteAddress") {
4686
+ // Result is the interned `string | undefined` union (envGet's).
4687
+ const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4688
+ const ok = def &&
4689
+ def.arms.length === 2 &&
4690
+ def.arms[0].kind === "string" &&
4691
+ def.arms[1].kind === "undefinedT";
4692
+ if (!ok) {
4693
+ err(`libCall net.sockRemoteAddress must return the 'string | undefined' union`, e.loc);
4694
+ }
4695
+ return true;
4696
+ }
4697
+ if (e.fn === "net.sockEncrypted") {
4698
+ // Result is the interned `boolean | undefined` union.
4699
+ const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4700
+ const ok = def &&
4701
+ def.arms.length === 2 &&
4702
+ def.arms[0].kind === "bool" &&
4703
+ def.arms[1].kind === "undefinedT";
4704
+ if (!ok) {
4705
+ err(`libCall net.sockEncrypted must return the 'boolean | undefined' union`, e.loc);
4706
+ }
4707
+ return true;
4708
+ }
4709
+ if (e.fn === "tls.sockAuthError") {
4710
+ // Result is the interned `string | null` union (Node's
4711
+ // authorizationError: the verify-failure code string, or null).
4712
+ const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4713
+ const ok = def &&
4714
+ def.arms.length === 2 &&
4715
+ def.arms[0].kind === "string" &&
4716
+ def.arms[1].kind === "nullT";
4717
+ if (!ok) {
4718
+ err(`libCall tls.sockAuthError must return the 'string | null' union`, e.loc);
4719
+ }
4720
+ return true;
4721
+ }
4722
+ if (e.fn === "http.requestCb" || e.fn === "https.requestCb" ||
4723
+ e.fn === "http.requestUrlCb" || e.fn === "http.clientOnResponse" ||
4724
+ e.fn === "http.requestAgentCb" || e.fn === "https.requestAgentCb" ||
4725
+ e.fn === "https.requestUrlCb") {
4726
+ // The response listener: void, no params or exactly (res: httpReq).
4727
+ const cbT = e.args[e.fn === "http.requestCb" ? 7
4728
+ : e.fn === "https.requestCb" ? 9
4729
+ : e.fn === "http.requestUrlCb" || e.fn === "https.requestUrlCb" ? 3
4730
+ : e.fn === "http.requestAgentCb" ? 8
4731
+ : e.fn === "https.requestAgentCb" ? 10
4732
+ : 1]?.type;
4733
+ let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= 1;
4734
+ if (ok && cbT?.kind === "func" && cbT.params.length === 1) {
4735
+ ok = cbT.params[0].kind === "httpReq";
4736
+ }
4737
+ if (!ok) {
4738
+ err(`libCall ${e.fn} callback shape (frontend must fence)`, e.loc);
4739
+ }
4740
+ return true;
4741
+ }
4742
+ if (e.fn === "http.reqOnError" || e.fn === "http.clientOnError") {
4743
+ // The error listener: void, no params or exactly (err: %Error).
4744
+ const cbT = e.args[1]?.type;
4745
+ let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= 1;
4746
+ if (ok && cbT?.kind === "func" && cbT.params.length === 1) {
4747
+ const p = cbT.params[0];
4748
+ ok = p.kind === "object" && p.className === "%Error";
4749
+ }
4750
+ if (!ok) {
4751
+ err(`libCall ${e.fn} callback shape (frontend must fence)`, e.loc);
4752
+ }
4753
+ return true;
4754
+ }
4755
+ if (e.fn === "net.sockRead") {
4756
+ // Result is the interned `Buffer | null` union.
4757
+ const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4758
+ const ok = def &&
4759
+ def.arms.length === 2 &&
4760
+ def.arms.some((a) => a.kind === "bytes" && a.elem === "u8") &&
4761
+ def.arms.some((a) => a.kind === "nullT");
4762
+ if (!ok) {
4763
+ err(`libCall net.sockRead must return the 'Buffer | null' union`, e.loc);
4764
+ }
4765
+ return true;
4766
+ }
4767
+ if (e.fn === "http.serverOnUpgrade" || e.fn === "http.clientOnUpgrade" ||
4768
+ e.fn === "http.serverOnConnect") {
4769
+ // (req, socket, head) or any shorter prefix, void return. The
4770
+ // 'connect' registration additionally admits a socket slot
4771
+ // that is a UNION carrying a netSocket arm (the h2 compat
4772
+ // listener — the emitted adapter wraps the socket there).
4773
+ const cbT = e.args[1]?.type;
4774
+ let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= 3;
4775
+ if (ok && cbT?.kind === "func") {
4776
+ const [p0, p1, p2] = cbT.params;
4777
+ if (p0 !== undefined && p0.kind !== "httpReq")
4778
+ ok = false;
4779
+ if (p1 !== undefined && p1.kind !== "netSocket") {
4780
+ if (e.fn === "http.serverOnConnect" && p1?.kind === "union") {
4781
+ const def = unions.get(p1.unionId);
4782
+ if (!def || !def.arms.some((a) => a.kind === "netSocket"))
4232
4783
  ok = false;
4233
4784
  }
4234
- if (!ok) {
4235
- err(`libCall ${e.fn} callback shape (frontend must fence)`, e.loc);
4236
- }
4237
- break;
4238
- }
4239
- if (e.fn === "net.listenOptsCb" || e.fn === "net.listenOptsReusePortCb") {
4240
- const cbIndex = e.fn === "net.listenOptsReusePortCb" ? 5 : 4;
4241
- const t = e.args[cbIndex]?.type;
4242
- const funcOk = (x) => x?.kind === "func" && x.params.length === 0 && x.ret.kind === "void";
4243
- let ok = funcOk(t);
4244
- if (!ok && t?.kind === "union") {
4245
- const def = unions.get(t.unionId);
4246
- ok = !!def && def.arms.length === 2 && def.arms.some((a) => funcOk(a)) &&
4247
- def.arms.some((a) => a.kind === "undefinedT");
4248
- }
4249
- if (!ok) {
4250
- err(`libCall ${e.fn} callback shape (frontend must fence)`, e.loc);
4251
- }
4252
- break;
4253
- }
4254
- if (e.fn === "net.connectLookup") {
4255
- // The caller's resolver: (hostname: string, options: unknown,
4256
- // callback: (err: <union>, addresses: <record[]>) => void) =>
4257
- // void — the emitter synthesizes the answer thunk from these
4258
- // types, so the structure must hold.
4259
- const t = e.args[2]?.type;
4260
- let ok = t?.kind === "func" && t.ret.kind === "void" && t.params.length === 3 &&
4261
- t.params[0].kind === "string" && t.params[1].kind === "dyn";
4262
- if (ok && t?.kind === "func") {
4263
- const cbT = t.params[2];
4264
- ok = cbT.kind === "func" && cbT.ret.kind === "void" && cbT.params.length === 2 &&
4265
- cbT.params[0].kind === "union" &&
4266
- cbT.params[1].kind === "array" && cbT.params[1].elem.kind === "record";
4267
- }
4268
- if (!ok) {
4269
- err(`libCall net.connectLookup resolver shape (frontend must fence)`, e.loc);
4270
- }
4271
- break;
4272
- }
4273
- if (e.fn === "http.requestConn" || e.fn === "http.requestConnCb") {
4274
- const dialT = e.args[0]?.type;
4275
- if (!(dialT?.kind === "func" && dialT.params.length === 0 && dialT.ret.kind === "netSocket")) {
4276
- err(`libCall ${e.fn} dialer shape (frontend must fence)`, e.loc);
4277
- break;
4278
- }
4279
- if (e.fn === "http.requestConnCb") {
4280
- const cbT = e.args[6]?.type;
4281
- const ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= 1 &&
4282
- (cbT.params[0] === undefined || cbT.params[0].kind === "httpReq");
4283
- if (!ok)
4284
- err(`libCall ${e.fn} callback shape (frontend must fence)`, e.loc);
4285
- }
4286
- break;
4287
- }
4288
- if (e.fn === "http.reqStatusMessage" || e.fn === "http.resStatusMsgGet") {
4289
- // Result is the interned `string | undefined` union (reqHeader's).
4290
- const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4291
- const ok = def &&
4292
- def.arms.length === 2 &&
4293
- def.arms.some((a) => a.kind === "string") &&
4294
- def.arms.some((a) => a.kind === "undefinedT");
4295
- if (!ok) {
4296
- err(`libCall ${e.fn} must return the 'string | undefined' union`, e.loc);
4785
+ else {
4786
+ ok = false;
4297
4787
  }
4298
- break;
4299
4788
  }
4300
- if (e.fn === "http.resSocket") {
4301
- const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4302
- const ok = def && def.arms.length === 2 &&
4303
- def.arms.some((a) => a.kind === "netSocket") &&
4304
- def.arms.some((a) => a.kind === "nullT");
4305
- if (!ok)
4306
- err(`libCall http.resSocket must return the 'Socket | null' union`, e.loc);
4307
- break;
4789
+ if (p2 !== undefined && !(p2.kind === "bytes" && p2.elem === "u8"))
4790
+ ok = false;
4791
+ }
4792
+ if (!ok) {
4793
+ err(`libCall ${e.fn} callback shape (frontend must fence)`, e.loc);
4794
+ }
4795
+ return true;
4796
+ }
4797
+ if (e.fn === "net.listenOptsCb" || e.fn === "net.listenOptsReusePortCb") {
4798
+ const cbIndex = e.fn === "net.listenOptsReusePortCb" ? 5 : 4;
4799
+ const t = e.args[cbIndex]?.type;
4800
+ const funcOk = (x) => x?.kind === "func" && x.params.length === 0 && x.ret.kind === "void";
4801
+ let ok = funcOk(t);
4802
+ if (!ok && t?.kind === "union") {
4803
+ const def = unions.get(t.unionId);
4804
+ ok = !!def && def.arms.length === 2 && def.arms.some((a) => funcOk(a)) &&
4805
+ def.arms.some((a) => a.kind === "undefinedT");
4806
+ }
4807
+ if (!ok) {
4808
+ err(`libCall ${e.fn} callback shape (frontend must fence)`, e.loc);
4809
+ }
4810
+ return true;
4811
+ }
4812
+ if (e.fn === "net.connectLookup") {
4813
+ // The caller's resolver: (hostname: string, options: unknown,
4814
+ // callback: (err: <union>, addresses: <record[]>) => void) =>
4815
+ // void — the emitter synthesizes the answer thunk from these
4816
+ // types, so the structure must hold.
4817
+ const t = e.args[2]?.type;
4818
+ let ok = t?.kind === "func" && t.ret.kind === "void" && t.params.length === 3 &&
4819
+ t.params[0].kind === "string" && t.params[1].kind === "dyn";
4820
+ if (ok && t?.kind === "func") {
4821
+ const cbT = t.params[2];
4822
+ ok = cbT.kind === "func" && cbT.ret.kind === "void" && cbT.params.length === 2 &&
4823
+ cbT.params[0].kind === "union" &&
4824
+ cbT.params[1].kind === "array" && cbT.params[1].elem.kind === "record";
4825
+ }
4826
+ if (!ok) {
4827
+ err(`libCall net.connectLookup resolver shape (frontend must fence)`, e.loc);
4828
+ }
4829
+ return true;
4830
+ }
4831
+ if (e.fn === "http.requestConn" || e.fn === "http.requestConnCb") {
4832
+ const dialT = e.args[0]?.type;
4833
+ if (!(dialT?.kind === "func" && dialT.params.length === 0 && dialT.ret.kind === "netSocket")) {
4834
+ err(`libCall ${e.fn} dialer shape (frontend must fence)`, e.loc);
4835
+ return true;
4836
+ }
4837
+ if (e.fn === "http.requestConnCb") {
4838
+ const cbT = e.args[6]?.type;
4839
+ const ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= 1 &&
4840
+ (cbT.params[0] === undefined || cbT.params[0].kind === "httpReq");
4841
+ if (!ok)
4842
+ err(`libCall ${e.fn} callback shape (frontend must fence)`, e.loc);
4843
+ }
4844
+ return true;
4845
+ }
4846
+ if (e.fn === "http.reqStatusMessage" || e.fn === "http.resStatusMsgGet") {
4847
+ // Result is the interned `string | undefined` union (reqHeader's).
4848
+ const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4849
+ const ok = def &&
4850
+ def.arms.length === 2 &&
4851
+ def.arms.some((a) => a.kind === "string") &&
4852
+ def.arms.some((a) => a.kind === "undefinedT");
4853
+ if (!ok) {
4854
+ err(`libCall ${e.fn} must return the 'string | undefined' union`, e.loc);
4855
+ }
4856
+ return true;
4857
+ }
4858
+ if (e.fn === "http.resSocket") {
4859
+ const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4860
+ const ok = def && def.arms.length === 2 &&
4861
+ def.arms.some((a) => a.kind === "netSocket") &&
4862
+ def.arms.some((a) => a.kind === "nullT");
4863
+ if (!ok)
4864
+ err(`libCall http.resSocket must return the 'Socket | null' union`, e.loc);
4865
+ return true;
4866
+ }
4867
+ if (e.fn === "http.reqH2Stream") {
4868
+ const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4869
+ const ok = def && def.arms.length === 2 &&
4870
+ def.arms.some((a) => a.kind === "http2Stream") &&
4871
+ def.arms.some((a) => a.kind === "undefinedT");
4872
+ if (!ok)
4873
+ err(`libCall http.reqH2Stream must return the 'Http2Stream | undefined' union`, e.loc);
4874
+ return true;
4875
+ }
4876
+ if (e.fn === "http.reqHeader" || e.fn === "http.reqTrailer" || e.fn === "http.resGetHeader" || e.fn === "http.clientGetHeader") {
4877
+ // Result is the interned `string | undefined` union (envGet's).
4878
+ const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4879
+ const ok = def &&
4880
+ def.arms.length === 2 &&
4881
+ def.arms[0].kind === "string" &&
4882
+ def.arms[1].kind === "undefinedT";
4883
+ if (!ok) {
4884
+ err(`libCall ${e.fn} must return the 'string | undefined' union`, e.loc);
4885
+ }
4886
+ return true;
4887
+ }
4888
+ if (e.fn === "http.reqHeaderValues" || e.fn === "http.reqTrailerValues") {
4889
+ const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4890
+ const ok = def && def.arms.length === 2 &&
4891
+ def.arms[0].kind === "array" && def.arms[0].elem.kind === "string" &&
4892
+ def.arms[1].kind === "undefinedT";
4893
+ if (!ok)
4894
+ err(`libCall ${e.fn} must return the 'string[] | undefined' union`, e.loc);
4895
+ return true;
4896
+ }
4897
+ if (e.fn === "net.createServerCb" || e.fn === "net.serverOnConnection" ||
4898
+ e.fn === "net.serverOnSecureConnection" ||
4899
+ e.fn === "http.serverSetTimeoutCb" || e.fn === "http.serverOnTimeout" ||
4900
+ e.fn === "http.clientOnSocket" ||
4901
+ e.fn === "net.sockOnData" || e.fn === "net.serverOnError" ||
4902
+ e.fn === "net.sockOnError") {
4903
+ // The program-dependent listener shapes: a void closure with no
4904
+ // params, or exactly the one supported parameter per event
4905
+ // (socket handle / data chunk bytes / error %Error). The
4906
+ // callback slot is arg 0 for createServerCb, arg 1 otherwise.
4907
+ const cbT = e.args[e.fn === "net.createServerCb" ? 0 : e.fn === "http.serverSetTimeoutCb" ? 2 : 1]?.type;
4908
+ let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= 1;
4909
+ if (ok && cbT?.kind === "func" && cbT.params.length === 1) {
4910
+ const p = cbT.params[0];
4911
+ if (e.fn === "net.sockOnData")
4912
+ ok = (p.kind === "bytes" && p.elem === "u8") || p.kind === "dyn";
4913
+ else if (e.fn === "net.serverOnError" || e.fn === "net.sockOnError") {
4914
+ ok = p.kind === "object" && p.className === "%Error";
4915
+ }
4916
+ else
4917
+ ok = p.kind === "netSocket";
4918
+ }
4919
+ if (!ok) {
4920
+ err(`libCall ${e.fn} callback shape (frontend must fence)`, e.loc);
4921
+ }
4922
+ return true;
4923
+ }
4924
+ if (e.fn === "http2.createSecureServerSni") {
4925
+ // The SNI callback: (servername: string, cb: (err, ctx?) => void)
4926
+ // => void — as a bare func, or the `| undefined` union from the
4927
+ // conditional-spread spelling (exactly two arms: the func and
4928
+ // undefined). The cb's own params are program-interned unions
4929
+ // (Error|null, SecureContext|undefined) whose arms the emitted
4930
+ // answer thunk decodes; here the structural func shape is what
4931
+ // the validator can pin.
4932
+ const sniOk = (t) => t?.kind === "func" && t.ret.kind === "void" && t.params.length === 2 &&
4933
+ t.params[0].kind === "string" && t.params[1].kind === "func";
4934
+ const argT = e.args[2]?.type;
4935
+ let ok = sniOk(argT);
4936
+ if (!ok && argT?.kind === "union") {
4937
+ const def = unions.get(argT.unionId);
4938
+ ok = def !== undefined && def.arms.length === 2 &&
4939
+ def.arms.some((a) => a.kind === "undefinedT") &&
4940
+ def.arms.some((a) => sniOk(a));
4941
+ }
4942
+ if (!ok) {
4943
+ err(`libCall ${e.fn} SNI callback shape (frontend must fence)`, e.loc);
4944
+ }
4945
+ return true;
4946
+ }
4947
+ if (e.fn === "dgram.onMessage" || e.fn === "dgram.onError") {
4948
+ // The dgram listener shapes: a void closure with no params, or
4949
+ // the per-event parameter shapes — message takes (msg: bytes<u8>
4950
+ // [, rinfo: record]), error the one %Error param.
4951
+ const cbT = e.args[1]?.type;
4952
+ const maxParams = e.fn === "dgram.onMessage" ? 2 : 1;
4953
+ let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= maxParams;
4954
+ if (ok && cbT?.kind === "func" && cbT.params.length >= 1) {
4955
+ if (e.fn === "dgram.onMessage") {
4956
+ const p0 = cbT.params[0];
4957
+ ok = p0.kind === "bytes" && p0.elem === "u8";
4958
+ const p1 = cbT.params[1];
4959
+ if (ok && p1 !== undefined)
4960
+ ok = p1.kind === "record";
4308
4961
  }
4309
- if (e.fn === "http.reqH2Stream") {
4310
- const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4311
- const ok = def && def.arms.length === 2 &&
4312
- def.arms.some((a) => a.kind === "http2Stream") &&
4313
- def.arms.some((a) => a.kind === "undefinedT");
4314
- if (!ok)
4315
- err(`libCall http.reqH2Stream must return the 'Http2Stream | undefined' union`, e.loc);
4316
- break;
4962
+ else {
4963
+ const p = cbT.params[0];
4964
+ ok = p.kind === "object" && p.className === "%Error";
4317
4965
  }
4318
- if (e.fn === "http.reqHeader" || e.fn === "http.reqTrailer" || e.fn === "http.resGetHeader" || e.fn === "http.clientGetHeader") {
4319
- // Result is the interned `string | undefined` union (envGet's).
4320
- const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4321
- const ok = def &&
4966
+ }
4967
+ if (!ok) {
4968
+ err(`libCall ${e.fn} callback shape (frontend must fence)`, e.loc);
4969
+ }
4970
+ return true;
4971
+ }
4972
+ if (e.fn === "dns.lookup") {
4973
+ // The callback: void, at most (err: Error | null, address:
4974
+ // string, family: number).
4975
+ const cbT = e.args[2]?.type;
4976
+ let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= 3;
4977
+ if (ok && cbT?.kind === "func" && cbT.params.length >= 1) {
4978
+ const p0 = cbT.params[0];
4979
+ const def = p0.kind === "union" ? unions.get(p0.unionId) : undefined;
4980
+ ok =
4981
+ def !== undefined &&
4322
4982
  def.arms.length === 2 &&
4323
- def.arms[0].kind === "string" &&
4324
- def.arms[1].kind === "undefinedT";
4325
- if (!ok) {
4326
- err(`libCall ${e.fn} must return the 'string | undefined' union`, e.loc);
4327
- }
4328
- break;
4983
+ def.arms.some((a) => a.kind === "nullT") &&
4984
+ def.arms.some((a) => a.kind === "object" && a.className === "%Error");
4985
+ const p1 = cbT.params[1];
4986
+ if (ok && p1 !== undefined)
4987
+ ok = p1.kind === "string";
4988
+ const p2 = cbT.params[2];
4989
+ if (ok && p2 !== undefined)
4990
+ ok = p2.kind === "f64";
4991
+ }
4992
+ if (!ok) {
4993
+ err(`libCall dns.lookup callback shape (frontend must fence)`, e.loc);
4994
+ }
4995
+ return true;
4996
+ }
4997
+ return false;
4998
+ }
4999
+ function checkLibFileCall(e) {
5000
+ if (e.fn === "zlib.deflateCb" || e.fn === "zlib.inflateCb" ||
5001
+ e.fn === "zlib.deflateRawCb" || e.fn === "zlib.inflateRawCb" ||
5002
+ e.fn === "zlib.gzipCb" || e.fn === "zlib.gunzipCb" || e.fn === "zlib.unzipCb") {
5003
+ const cbT = e.args[1]?.type;
5004
+ let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= 2;
5005
+ if (ok && cbT?.kind === "func" && cbT.params.length >= 1) {
5006
+ const error = cbT.params[0];
5007
+ if (error.kind !== "dyn") {
5008
+ const def = error.kind === "union" ? unions.get(error.unionId) : undefined;
5009
+ ok = def !== undefined &&
5010
+ def.arms.some((arm) => arm.kind === "nullT") &&
5011
+ def.arms.some((arm) => arm.kind === "object" && arm.className === "%Error") &&
5012
+ def.arms.every((arm) => arm.kind === "nullT" || arm.kind === "undefinedT" ||
5013
+ (arm.kind === "object" && arm.className === "%Error"));
5014
+ }
5015
+ }
5016
+ if (ok && cbT?.kind === "func" && cbT.params.length === 2) {
5017
+ const value = cbT.params[1];
5018
+ ok = value.kind === "dyn" || (value.kind === "bytes" && value.elem === "u8");
5019
+ }
5020
+ if (!ok)
5021
+ err(`libCall ${e.fn} callback shape (frontend must fence)`, e.loc);
5022
+ return true;
5023
+ }
5024
+ if (e.fn === "fs.renameCb" ||
5025
+ e.fn === "process.stdoutWriteBytesCb" ||
5026
+ e.fn === "process.stderrWriteBytesCb") {
5027
+ // The callback is void and accepts either no parameters, one
5028
+ // checked-dynamic error slot (JS), or Error | null (optionally
5029
+ // including undefined for an explicitly optional parameter).
5030
+ const cbT = e.args[2]?.type;
5031
+ let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= 1;
5032
+ if (ok && cbT?.kind === "func" && cbT.params.length === 1) {
5033
+ const p = cbT.params[0];
5034
+ if (p.kind === "dyn") {
5035
+ ok = true;
4329
5036
  }
4330
- if (e.fn === "http.reqHeaderValues" || e.fn === "http.reqTrailerValues") {
4331
- const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4332
- const ok = def && def.arms.length === 2 &&
4333
- def.arms[0].kind === "array" && def.arms[0].elem.kind === "string" &&
4334
- def.arms[1].kind === "undefinedT";
4335
- if (!ok)
4336
- err(`libCall ${e.fn} must return the 'string[] | undefined' union`, e.loc);
4337
- break;
5037
+ else {
5038
+ const def = p.kind === "union" ? unions.get(p.unionId) : undefined;
5039
+ ok =
5040
+ def !== undefined &&
5041
+ def.arms.some((a) => a.kind === "nullT") &&
5042
+ def.arms.some((a) => a.kind === "object" && a.className === "%Error") &&
5043
+ def.arms.every((a) => a.kind === "nullT" || a.kind === "undefinedT" ||
5044
+ (a.kind === "object" && a.className === "%Error"));
4338
5045
  }
4339
- if (e.fn === "net.createServerCb" || e.fn === "net.serverOnConnection" ||
4340
- e.fn === "net.serverOnSecureConnection" ||
4341
- e.fn === "http.serverSetTimeoutCb" || e.fn === "http.serverOnTimeout" ||
4342
- e.fn === "http.clientOnSocket" ||
4343
- e.fn === "net.sockOnData" || e.fn === "net.serverOnError" ||
4344
- e.fn === "net.sockOnError") {
4345
- // The program-dependent listener shapes: a void closure with no
4346
- // params, or exactly the one supported parameter per event
4347
- // (socket handle / data chunk bytes / error %Error). The
4348
- // callback slot is arg 0 for createServerCb, arg 1 otherwise.
4349
- const cbT = e.args[e.fn === "net.createServerCb" ? 0 : e.fn === "http.serverSetTimeoutCb" ? 2 : 1]?.type;
4350
- let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= 1;
4351
- if (ok && cbT?.kind === "func" && cbT.params.length === 1) {
4352
- const p = cbT.params[0];
4353
- if (e.fn === "net.sockOnData")
4354
- ok = (p.kind === "bytes" && p.elem === "u8") || p.kind === "dyn";
4355
- else if (e.fn === "net.serverOnError" || e.fn === "net.sockOnError") {
4356
- ok = p.kind === "object" && p.className === "%Error";
4357
- }
4358
- else
4359
- ok = p.kind === "netSocket";
4360
- }
4361
- if (!ok) {
4362
- err(`libCall ${e.fn} callback shape (frontend must fence)`, e.loc);
5046
+ }
5047
+ if (!ok) {
5048
+ err(`libCall ${e.fn} callback shape (frontend must fence)`, e.loc);
5049
+ }
5050
+ return true;
5051
+ }
5052
+ if (e.fn === "net.serverAddress") {
5053
+ // Result is the {address, family, port} record (dgram.address's
5054
+ // check, another receiver).
5055
+ const shape = e.type.kind === "record" ? records.get(e.type.shapeId) : undefined;
5056
+ const ok = shape !== undefined &&
5057
+ shape.fields.length === 3 &&
5058
+ shape.fields[0].name === "address" && shape.fields[0].type.kind === "string" &&
5059
+ shape.fields[1].name === "family" && shape.fields[1].type.kind === "string" &&
5060
+ shape.fields[2].name === "port" && shape.fields[2].type.kind === "f64";
5061
+ if (!ok) {
5062
+ err(`libCall net.serverAddress must return the {address, family, port} record`, e.loc);
5063
+ }
5064
+ return true;
5065
+ }
5066
+ if (e.fn === "dgram.address") {
5067
+ // Result is the {address, family, port} record.
5068
+ const shape = e.type.kind === "record" ? records.get(e.type.shapeId) : undefined;
5069
+ const ok = shape !== undefined &&
5070
+ shape.fields.length === 3 &&
5071
+ shape.fields[0].name === "address" && shape.fields[0].type.kind === "string" &&
5072
+ shape.fields[1].name === "family" && shape.fields[1].type.kind === "string" &&
5073
+ shape.fields[2].name === "port" && shape.fields[2].type.kind === "f64";
5074
+ if (!ok) {
5075
+ err(`libCall dgram.address must return the {address, family, port} record`, e.loc);
5076
+ }
5077
+ return true;
5078
+ }
5079
+ if (e.fn === "fs.readdirTypesSync" || e.fn === "fsp.readdirTypes") {
5080
+ // Result: the interned Dirent record array — {%dtype: f64,
5081
+ // name: string, parentPath: string} rows (canonical field
5082
+ // order; the structure lowerFsReaddirTypesCall pinned).
5083
+ const result = e.fn === "fsp.readdirTypes"
5084
+ ? e.type.kind === "promise" ? e.type.inner : undefined
5085
+ : e.type;
5086
+ const shape = result?.kind === "array" && result.elem.kind === "record"
5087
+ ? records.get(result.elem.shapeId)
5088
+ : undefined;
5089
+ const ok = shape !== undefined &&
5090
+ !shape.tuple &&
5091
+ shape.indexValue === undefined &&
5092
+ shape.fields.length === 3 &&
5093
+ shape.fields[0].name === "%dtype" && shape.fields[0].type.kind === "f64" &&
5094
+ shape.fields[1].name === "name" && shape.fields[1].type.kind === "string" &&
5095
+ shape.fields[2].name === "parentPath" && shape.fields[2].type.kind === "string";
5096
+ if (!ok) {
5097
+ err(`libCall ${e.fn} must return ${e.fn === "fsp.readdirTypes" ? "a promise of " : ""}the Dirent record array`, e.loc);
5098
+ }
5099
+ return true;
5100
+ }
5101
+ if (e.fn === "os.networkInterfaces") {
5102
+ // Result: a pure index-signature record whose value is
5103
+ // `Info[] | undefined`, Info a two-record union (one arm's
5104
+ // scopeid f64, the other's `number | undefined`) — the structure
5105
+ // lowerOsNetworkInterfacesCall pinned.
5106
+ const shape = e.type.kind === "record" ? records.get(e.type.shapeId) : undefined;
5107
+ let ok = shape !== undefined && !shape.tuple && shape.fields.length === 0 && shape.indexValue !== undefined;
5108
+ const ivDef = ok && shape.indexValue.kind === "union" ? unions.get(shape.indexValue.unionId) : undefined;
5109
+ const arrArm = ivDef?.arms.find((a) => a.kind === "array");
5110
+ ok = ok && ivDef !== undefined && ivDef.arms.length === 2 && arrArm !== undefined && ivDef.arms.some((a) => a.kind === "undefinedT");
5111
+ const infoDef = ok && arrArm.kind === "array" && arrArm.elem.kind === "union" ? unions.get(arrArm.elem.unionId) : undefined;
5112
+ ok = ok && infoDef !== undefined && infoDef.arms.length === 2 && infoDef.arms.every((a) => a.kind === "record");
5113
+ if (!ok) {
5114
+ err(`libCall os.networkInterfaces must return the NetworkInterfaceInfo dictionary record`, e.loc);
5115
+ }
5116
+ return true;
5117
+ }
5118
+ if (e.fn === "qs.parse") {
5119
+ // Result: a pure index-signature record whose value union
5120
+ // carries a string arm and a string[] arm (undefined tolerated
5121
+ // — @types/node's Dict — and f64 too: the header-family
5122
+ // canonicalization interns every such dictionary with the
5123
+ // number arm, type-level only) — the structure
5124
+ // lowerQuerystringParseCall pinned.
5125
+ const shape = e.type.kind === "record" ? records.get(e.type.shapeId) : undefined;
5126
+ let ok = shape !== undefined && !shape.tuple && shape.fields.length === 0 && shape.indexValue !== undefined;
5127
+ const ivDef = ok && shape.indexValue.kind === "union" ? unions.get(shape.indexValue.unionId) : undefined;
5128
+ ok = ok && ivDef !== undefined &&
5129
+ ivDef.arms.some((a) => a.kind === "string") &&
5130
+ ivDef.arms.some((a) => a.kind === "array" && a.elem.kind === "string") &&
5131
+ ivDef.arms.every((a) => a.kind === "string" || a.kind === "array" || a.kind === "undefinedT" || a.kind === "f64");
5132
+ if (!ok) {
5133
+ err(`libCall qs.parse must return the ParsedUrlQuery dictionary record`, e.loc);
5134
+ }
5135
+ return true;
5136
+ }
5137
+ return false;
5138
+ }
5139
+ function checkLibProcessCall(e) {
5140
+ if (e.fn === "cp.execFile") {
5141
+ const cb = e.args[2]?.type;
5142
+ if (cb?.kind !== "func" || cb.rest === true || cb.params.length > 3 || cb.ret.kind !== "void") {
5143
+ err(`libCall cp.execFile callback must be a non-rest void function with at most three parameters`, e.loc);
5144
+ }
5145
+ else {
5146
+ const error = cb.params[0];
5147
+ if (error !== undefined) {
5148
+ const def = error.kind === "union" ? unions.get(error.unionId) : undefined;
5149
+ if (!def || def.arms.length !== 2 ||
5150
+ !def.arms.some((arm) => arm.kind === "nullT") ||
5151
+ !def.arms.some((arm) => arm.kind === "object" && arm.className === "%Error")) {
5152
+ err(`libCall cp.execFile callback error parameter must be Error | null`, e.loc);
4363
5153
  }
4364
- break;
4365
5154
  }
4366
- if (e.fn === "http2.createSecureServerSni") {
4367
- // The SNI callback: (servername: string, cb: (err, ctx?) => void)
4368
- // => void — as a bare func, or the `| undefined` union from the
4369
- // conditional-spread spelling (exactly two arms: the func and
4370
- // undefined). The cb's own params are program-interned unions
4371
- // (Error|null, SecureContext|undefined) whose arms the emitted
4372
- // answer thunk decodes; here the structural func shape is what
4373
- // the validator can pin.
4374
- const sniOk = (t) => t?.kind === "func" && t.ret.kind === "void" && t.params.length === 2 &&
4375
- t.params[0].kind === "string" && t.params[1].kind === "func";
4376
- const argT = e.args[2]?.type;
4377
- let ok = sniOk(argT);
4378
- if (!ok && argT?.kind === "union") {
4379
- const def = unions.get(argT.unionId);
4380
- ok = def !== undefined && def.arms.length === 2 &&
4381
- def.arms.some((a) => a.kind === "undefinedT") &&
4382
- def.arms.some((a) => sniOk(a));
4383
- }
4384
- if (!ok) {
4385
- err(`libCall ${e.fn} SNI callback shape (frontend must fence)`, e.loc);
4386
- }
4387
- break;
5155
+ const stdout = cb.params[1];
5156
+ if (stdout !== undefined && stdout.kind !== "string") {
5157
+ err(`libCall cp.execFile callback stdout parameter must be string`, e.loc);
4388
5158
  }
4389
- if (e.fn === "dgram.onMessage" || e.fn === "dgram.onError") {
4390
- // The dgram listener shapes: a void closure with no params, or
4391
- // the per-event parameter shapes — message takes (msg: bytes<u8>
4392
- // [, rinfo: record]), error the one %Error param.
4393
- const cbT = e.args[1]?.type;
4394
- const maxParams = e.fn === "dgram.onMessage" ? 2 : 1;
4395
- let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= maxParams;
4396
- if (ok && cbT?.kind === "func" && cbT.params.length >= 1) {
4397
- if (e.fn === "dgram.onMessage") {
4398
- const p0 = cbT.params[0];
4399
- ok = p0.kind === "bytes" && p0.elem === "u8";
4400
- const p1 = cbT.params[1];
4401
- if (ok && p1 !== undefined)
4402
- ok = p1.kind === "record";
4403
- }
4404
- else {
4405
- const p = cbT.params[0];
4406
- ok = p.kind === "object" && p.className === "%Error";
4407
- }
4408
- }
4409
- if (!ok) {
4410
- err(`libCall ${e.fn} callback shape (frontend must fence)`, e.loc);
4411
- }
4412
- break;
5159
+ const stderr = cb.params[2];
5160
+ if (stderr !== undefined && stderr.kind !== "string") {
5161
+ err(`libCall cp.execFile callback stderr parameter must be string`, e.loc);
4413
5162
  }
4414
- if (e.fn === "dns.lookup") {
4415
- // The callback: void, at most (err: Error | null, address:
4416
- // string, family: number).
4417
- const cbT = e.args[2]?.type;
4418
- let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= 3;
4419
- if (ok && cbT?.kind === "func" && cbT.params.length >= 1) {
4420
- const p0 = cbT.params[0];
4421
- const def = p0.kind === "union" ? unions.get(p0.unionId) : undefined;
5163
+ }
5164
+ }
5165
+ if (e.fn === "child.onExit" || e.fn === "child.onClose" || e.fn === "child.onError") {
5166
+ // The listener: a closure with no params, or exactly the
5167
+ // supported parameter shapes per event — exit takes (code:
5168
+ // number | null) with an optional (signal: string | null)
5169
+ // second parameter, error exactly (err: %Error).
5170
+ const cb = e.args[1];
5171
+ const cbT = cb?.type;
5172
+ const maxParams = e.fn === "child.onError" ? 1 : 2;
5173
+ let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= maxParams;
5174
+ if (ok && cbT?.kind === "func" && cbT.params.length >= 1) {
5175
+ const p = cbT.params[0];
5176
+ if (e.fn === "child.onExit" || e.fn === "child.onClose") {
5177
+ const def = p.kind === "union" ? unions.get(p.unionId) : undefined;
5178
+ ok =
5179
+ def !== undefined &&
5180
+ def.arms.length === 2 &&
5181
+ def.arms[0].kind === "f64" &&
5182
+ def.arms[1].kind === "nullT";
5183
+ if (ok && cbT.params.length === 2) {
5184
+ const s = cbT.params[1];
5185
+ const sdef = s.kind === "union" ? unions.get(s.unionId) : undefined;
4422
5186
  ok =
4423
- def !== undefined &&
4424
- def.arms.length === 2 &&
4425
- def.arms.some((a) => a.kind === "nullT") &&
4426
- def.arms.some((a) => a.kind === "object" && a.className === "%Error");
4427
- const p1 = cbT.params[1];
4428
- if (ok && p1 !== undefined)
4429
- ok = p1.kind === "string";
4430
- const p2 = cbT.params[2];
4431
- if (ok && p2 !== undefined)
4432
- ok = p2.kind === "f64";
4433
- }
4434
- if (!ok) {
4435
- err(`libCall dns.lookup callback shape (frontend must fence)`, e.loc);
4436
- }
4437
- break;
4438
- }
4439
- if (e.fn === "zlib.deflateCb" || e.fn === "zlib.inflateCb" ||
4440
- e.fn === "zlib.deflateRawCb" || e.fn === "zlib.inflateRawCb" ||
4441
- e.fn === "zlib.gzipCb" || e.fn === "zlib.gunzipCb" || e.fn === "zlib.unzipCb") {
4442
- const cbT = e.args[1]?.type;
4443
- let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= 2;
4444
- if (ok && cbT?.kind === "func" && cbT.params.length >= 1) {
4445
- const error = cbT.params[0];
4446
- if (error.kind !== "dyn") {
4447
- const def = error.kind === "union" ? unions.get(error.unionId) : undefined;
4448
- ok = def !== undefined &&
4449
- def.arms.some((arm) => arm.kind === "nullT") &&
4450
- def.arms.some((arm) => arm.kind === "object" && arm.className === "%Error") &&
4451
- def.arms.every((arm) => arm.kind === "nullT" || arm.kind === "undefinedT" ||
4452
- (arm.kind === "object" && arm.className === "%Error"));
4453
- }
4454
- }
4455
- if (ok && cbT?.kind === "func" && cbT.params.length === 2) {
4456
- const value = cbT.params[1];
4457
- ok = value.kind === "dyn" || (value.kind === "bytes" && value.elem === "u8");
4458
- }
4459
- if (!ok)
4460
- err(`libCall ${e.fn} callback shape (frontend must fence)`, e.loc);
4461
- break;
4462
- }
4463
- if (e.fn === "fs.renameCb" ||
4464
- e.fn === "process.stdoutWriteBytesCb" ||
4465
- e.fn === "process.stderrWriteBytesCb") {
4466
- // The callback is void and accepts either no parameters, one
4467
- // checked-dynamic error slot (JS), or Error | null (optionally
4468
- // including undefined for an explicitly optional parameter).
4469
- const cbT = e.args[2]?.type;
4470
- let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= 1;
4471
- if (ok && cbT?.kind === "func" && cbT.params.length === 1) {
4472
- const p = cbT.params[0];
4473
- if (p.kind === "dyn") {
4474
- ok = true;
4475
- }
4476
- else {
4477
- const def = p.kind === "union" ? unions.get(p.unionId) : undefined;
4478
- ok =
4479
- def !== undefined &&
4480
- def.arms.some((a) => a.kind === "nullT") &&
4481
- def.arms.some((a) => a.kind === "object" && a.className === "%Error") &&
4482
- def.arms.every((a) => a.kind === "nullT" || a.kind === "undefinedT" ||
4483
- (a.kind === "object" && a.className === "%Error"));
4484
- }
4485
- }
4486
- if (!ok) {
4487
- err(`libCall ${e.fn} callback shape (frontend must fence)`, e.loc);
4488
- }
4489
- break;
4490
- }
4491
- if (e.fn === "net.serverAddress") {
4492
- // Result is the {address, family, port} record (dgram.address's
4493
- // check, another receiver).
4494
- const shape = e.type.kind === "record" ? records.get(e.type.shapeId) : undefined;
4495
- const ok = shape !== undefined &&
4496
- shape.fields.length === 3 &&
4497
- shape.fields[0].name === "address" && shape.fields[0].type.kind === "string" &&
4498
- shape.fields[1].name === "family" && shape.fields[1].type.kind === "string" &&
4499
- shape.fields[2].name === "port" && shape.fields[2].type.kind === "f64";
4500
- if (!ok) {
4501
- err(`libCall net.serverAddress must return the {address, family, port} record`, e.loc);
4502
- }
4503
- break;
4504
- }
4505
- if (e.fn === "dgram.address") {
4506
- // Result is the {address, family, port} record.
4507
- const shape = e.type.kind === "record" ? records.get(e.type.shapeId) : undefined;
4508
- const ok = shape !== undefined &&
4509
- shape.fields.length === 3 &&
4510
- shape.fields[0].name === "address" && shape.fields[0].type.kind === "string" &&
4511
- shape.fields[1].name === "family" && shape.fields[1].type.kind === "string" &&
4512
- shape.fields[2].name === "port" && shape.fields[2].type.kind === "f64";
4513
- if (!ok) {
4514
- err(`libCall dgram.address must return the {address, family, port} record`, e.loc);
4515
- }
4516
- break;
4517
- }
4518
- if (e.fn === "fs.readdirTypesSync" || e.fn === "fsp.readdirTypes") {
4519
- // Result: the interned Dirent record array — {%dtype: f64,
4520
- // name: string, parentPath: string} rows (canonical field
4521
- // order; the structure lowerFsReaddirTypesCall pinned).
4522
- const result = e.fn === "fsp.readdirTypes"
4523
- ? e.type.kind === "promise" ? e.type.inner : undefined
4524
- : e.type;
4525
- const shape = result?.kind === "array" && result.elem.kind === "record"
4526
- ? records.get(result.elem.shapeId)
4527
- : undefined;
4528
- const ok = shape !== undefined &&
4529
- !shape.tuple &&
4530
- shape.indexValue === undefined &&
4531
- shape.fields.length === 3 &&
4532
- shape.fields[0].name === "%dtype" && shape.fields[0].type.kind === "f64" &&
4533
- shape.fields[1].name === "name" && shape.fields[1].type.kind === "string" &&
4534
- shape.fields[2].name === "parentPath" && shape.fields[2].type.kind === "string";
4535
- if (!ok) {
4536
- err(`libCall ${e.fn} must return ${e.fn === "fsp.readdirTypes" ? "a promise of " : ""}the Dirent record array`, e.loc);
4537
- }
4538
- break;
4539
- }
4540
- if (e.fn === "os.networkInterfaces") {
4541
- // Result: a pure index-signature record whose value is
4542
- // `Info[] | undefined`, Info a two-record union (one arm's
4543
- // scopeid f64, the other's `number | undefined`) — the structure
4544
- // lowerOsNetworkInterfacesCall pinned.
4545
- const shape = e.type.kind === "record" ? records.get(e.type.shapeId) : undefined;
4546
- let ok = shape !== undefined && !shape.tuple && shape.fields.length === 0 && shape.indexValue !== undefined;
4547
- const ivDef = ok && shape.indexValue.kind === "union" ? unions.get(shape.indexValue.unionId) : undefined;
4548
- const arrArm = ivDef?.arms.find((a) => a.kind === "array");
4549
- ok = ok && ivDef !== undefined && ivDef.arms.length === 2 && arrArm !== undefined && ivDef.arms.some((a) => a.kind === "undefinedT");
4550
- const infoDef = ok && arrArm.kind === "array" && arrArm.elem.kind === "union" ? unions.get(arrArm.elem.unionId) : undefined;
4551
- ok = ok && infoDef !== undefined && infoDef.arms.length === 2 && infoDef.arms.every((a) => a.kind === "record");
4552
- if (!ok) {
4553
- err(`libCall os.networkInterfaces must return the NetworkInterfaceInfo dictionary record`, e.loc);
4554
- }
4555
- break;
4556
- }
4557
- if (e.fn === "qs.parse") {
4558
- // Result: a pure index-signature record whose value union
4559
- // carries a string arm and a string[] arm (undefined tolerated
4560
- // — @types/node's Dict — and f64 too: the header-family
4561
- // canonicalization interns every such dictionary with the
4562
- // number arm, type-level only) — the structure
4563
- // lowerQuerystringParseCall pinned.
4564
- const shape = e.type.kind === "record" ? records.get(e.type.shapeId) : undefined;
4565
- let ok = shape !== undefined && !shape.tuple && shape.fields.length === 0 && shape.indexValue !== undefined;
4566
- const ivDef = ok && shape.indexValue.kind === "union" ? unions.get(shape.indexValue.unionId) : undefined;
4567
- ok = ok && ivDef !== undefined &&
4568
- ivDef.arms.some((a) => a.kind === "string") &&
4569
- ivDef.arms.some((a) => a.kind === "array" && a.elem.kind === "string") &&
4570
- ivDef.arms.every((a) => a.kind === "string" || a.kind === "array" || a.kind === "undefinedT" || a.kind === "f64");
4571
- if (!ok) {
4572
- err(`libCall qs.parse must return the ParsedUrlQuery dictionary record`, e.loc);
4573
- }
4574
- break;
4575
- }
4576
- if (e.fn === "cp.execFile") {
4577
- const cb = e.args[2]?.type;
4578
- if (cb?.kind !== "func" || cb.rest === true || cb.params.length > 3 || cb.ret.kind !== "void") {
4579
- err(`libCall cp.execFile callback must be a non-rest void function with at most three parameters`, e.loc);
4580
- }
4581
- else {
4582
- const error = cb.params[0];
4583
- if (error !== undefined) {
4584
- const def = error.kind === "union" ? unions.get(error.unionId) : undefined;
4585
- if (!def || def.arms.length !== 2 ||
4586
- !def.arms.some((arm) => arm.kind === "nullT") ||
4587
- !def.arms.some((arm) => arm.kind === "object" && arm.className === "%Error")) {
4588
- err(`libCall cp.execFile callback error parameter must be Error | null`, e.loc);
4589
- }
4590
- }
4591
- const stdout = cb.params[1];
4592
- if (stdout !== undefined && stdout.kind !== "string") {
4593
- err(`libCall cp.execFile callback stdout parameter must be string`, e.loc);
4594
- }
4595
- const stderr = cb.params[2];
4596
- if (stderr !== undefined && stderr.kind !== "string") {
4597
- err(`libCall cp.execFile callback stderr parameter must be string`, e.loc);
4598
- }
5187
+ sdef !== undefined &&
5188
+ sdef.arms.length === 2 &&
5189
+ sdef.arms.some((a) => a.kind === "string") &&
5190
+ sdef.arms.some((a) => a.kind === "nullT");
4599
5191
  }
4600
5192
  }
4601
- if (e.fn === "child.onExit" || e.fn === "child.onClose" || e.fn === "child.onError") {
4602
- // The listener: a closure with no params, or exactly the
4603
- // supported parameter shapes per event — exit takes (code:
4604
- // number | null) with an optional (signal: string | null)
4605
- // second parameter, error exactly (err: %Error).
4606
- const cb = e.args[1];
4607
- const cbT = cb?.type;
4608
- const maxParams = e.fn === "child.onError" ? 1 : 2;
4609
- let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= maxParams;
4610
- if (ok && cbT?.kind === "func" && cbT.params.length >= 1) {
4611
- const p = cbT.params[0];
4612
- if (e.fn === "child.onExit" || e.fn === "child.onClose") {
4613
- const def = p.kind === "union" ? unions.get(p.unionId) : undefined;
4614
- ok =
4615
- def !== undefined &&
4616
- def.arms.length === 2 &&
4617
- def.arms[0].kind === "f64" &&
4618
- def.arms[1].kind === "nullT";
4619
- if (ok && cbT.params.length === 2) {
4620
- const s = cbT.params[1];
4621
- const sdef = s.kind === "union" ? unions.get(s.unionId) : undefined;
4622
- ok =
4623
- sdef !== undefined &&
4624
- sdef.arms.length === 2 &&
4625
- sdef.arms.some((a) => a.kind === "string") &&
4626
- sdef.arms.some((a) => a.kind === "nullT");
4627
- }
4628
- }
4629
- else {
4630
- ok = p.kind === "object" && p.className === "%Error";
4631
- }
4632
- }
4633
- if (!ok) {
4634
- err(`libCall ${e.fn} callback shape (frontend must fence)`, e.loc);
4635
- }
4636
- break;
4637
- }
4638
- if (e.fn === "writer.onDrain" || e.fn === "writer.onFinish" || e.fn === "writer.onError") {
4639
- const cbT = e.args[1]?.type;
4640
- const maxParams = e.fn === "writer.onError" ? 1 : 0;
4641
- let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= maxParams;
4642
- if (ok && cbT?.kind === "func" && cbT.params.length === 1) {
4643
- const p = cbT.params[0];
4644
- ok = p.kind === "object" && p.className === "%Error";
4645
- }
4646
- if (!ok)
4647
- err(`libCall ${e.fn} callback shape (frontend must fence)`, e.loc);
4648
- break;
4649
- }
4650
- if (e.fn === "process.onExit" || e.fn === "process.offExit" ||
4651
- e.fn === "stdin.onData" || e.fn === "stdin.onError") {
4652
- // The listener: a void closure with no params, or exactly the
4653
- // one supported parameter shape per event (code number / data
4654
- // chunk bytes / error %Error).
4655
- const cbT = e.args[0]?.type;
4656
- let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= 1;
4657
- if (ok && cbT?.kind === "func" && cbT.params.length === 1) {
4658
- const p = cbT.params[0];
4659
- if (e.fn === "stdin.onData")
4660
- ok = p.kind === "bytes" && p.elem === "u8";
4661
- else if (e.fn === "stdin.onError")
4662
- ok = p.kind === "object" && p.className === "%Error";
4663
- else
4664
- ok = p.kind === "f64";
4665
- }
4666
- if (!ok) {
4667
- err(`libCall ${e.fn} callback shape (frontend must fence)`, e.loc);
4668
- }
4669
- break;
4670
- }
4671
- if (e.fn === "spawnRes.status") {
4672
- // Result is the module's interned `number | null` union.
4673
- const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4674
- const ok = def &&
4675
- def.arms.length === 2 &&
4676
- def.arms[0].kind === "f64" &&
4677
- def.arms[1].kind === "nullT";
4678
- if (!ok) {
4679
- err(`libCall spawnRes.status must return the 'number | null' union`, e.loc);
4680
- }
4681
- break;
5193
+ else {
5194
+ ok = p.kind === "object" && p.className === "%Error";
4682
5195
  }
4683
- if (e.fn === "spawnRes.signal") {
4684
- // Result is the module's interned `string | null` union.
4685
- const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4686
- const ok = def &&
4687
- def.arms.length === 2 &&
4688
- def.arms.some((a) => a.kind === "string") &&
4689
- def.arms.some((a) => a.kind === "nullT");
4690
- if (!ok) {
4691
- err(`libCall spawnRes.signal must return the 'string | null' union`, e.loc);
5196
+ }
5197
+ if (!ok) {
5198
+ err(`libCall ${e.fn} callback shape (frontend must fence)`, e.loc);
5199
+ }
5200
+ return true;
5201
+ }
5202
+ if (e.fn === "writer.onDrain" || e.fn === "writer.onFinish" || e.fn === "writer.onError") {
5203
+ const cbT = e.args[1]?.type;
5204
+ const maxParams = e.fn === "writer.onError" ? 1 : 0;
5205
+ let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= maxParams;
5206
+ if (ok && cbT?.kind === "func" && cbT.params.length === 1) {
5207
+ const p = cbT.params[0];
5208
+ ok = p.kind === "object" && p.className === "%Error";
5209
+ }
5210
+ if (!ok)
5211
+ err(`libCall ${e.fn} callback shape (frontend must fence)`, e.loc);
5212
+ return true;
5213
+ }
5214
+ if (e.fn === "process.onExit" || e.fn === "process.offExit" ||
5215
+ e.fn === "stdin.onData" || e.fn === "stdin.onError") {
5216
+ // The listener: a void closure with no params, or exactly the
5217
+ // one supported parameter shape per event (code number / data
5218
+ // chunk bytes / error %Error).
5219
+ const cbT = e.args[0]?.type;
5220
+ let ok = cbT?.kind === "func" && cbT.ret.kind === "void" && cbT.params.length <= 1;
5221
+ if (ok && cbT?.kind === "func" && cbT.params.length === 1) {
5222
+ const p = cbT.params[0];
5223
+ if (e.fn === "stdin.onData")
5224
+ ok = p.kind === "bytes" && p.elem === "u8";
5225
+ else if (e.fn === "stdin.onError")
5226
+ ok = p.kind === "object" && p.className === "%Error";
5227
+ else
5228
+ ok = p.kind === "f64";
5229
+ }
5230
+ if (!ok) {
5231
+ err(`libCall ${e.fn} callback shape (frontend must fence)`, e.loc);
5232
+ }
5233
+ return true;
5234
+ }
5235
+ if (e.fn === "spawnRes.status") {
5236
+ // Result is the module's interned `number | null` union.
5237
+ const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
5238
+ const ok = def &&
5239
+ def.arms.length === 2 &&
5240
+ def.arms[0].kind === "f64" &&
5241
+ def.arms[1].kind === "nullT";
5242
+ if (!ok) {
5243
+ err(`libCall spawnRes.status must return the 'number | null' union`, e.loc);
5244
+ }
5245
+ return true;
5246
+ }
5247
+ if (e.fn === "spawnRes.signal") {
5248
+ // Result is the module's interned `string | null` union.
5249
+ const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
5250
+ const ok = def &&
5251
+ def.arms.length === 2 &&
5252
+ def.arms.some((a) => a.kind === "string") &&
5253
+ def.arms.some((a) => a.kind === "nullT");
5254
+ if (!ok) {
5255
+ err(`libCall spawnRes.signal must return the 'string | null' union`, e.loc);
5256
+ }
5257
+ return true;
5258
+ }
5259
+ if (e.fn === "sp.get") {
5260
+ // Result is the interned `string | null` union (the runtime
5261
+ // answers +1-or-NULL; the backend builds the arms).
5262
+ const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
5263
+ const ok = def &&
5264
+ def.arms.length === 2 &&
5265
+ def.arms.some((a) => a.kind === "string") &&
5266
+ def.arms.some((a) => a.kind === "nullT");
5267
+ if (!ok) {
5268
+ err(`libCall sp.get must return the 'string | null' union`, e.loc);
5269
+ }
5270
+ return true;
5271
+ }
5272
+ if (e.fn === "sp.fromPairs") {
5273
+ const t = e.args[0]?.type;
5274
+ const ok = t && t.kind === "array" && t.elem.kind === "array" && t.elem.elem.kind === "string";
5275
+ if (!ok) {
5276
+ err(`libCall sp.fromPairs arg 0: expected string[][], got ${t?.kind}`, e.loc);
5277
+ }
5278
+ return true;
5279
+ }
5280
+ if (e.fn === "sym.desc" || e.fn === "sym.keyFor") {
5281
+ // Result is the interned `string | undefined` union (the
5282
+ // runtime answers +1-or-NULL; the backend builds the arms).
5283
+ const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
5284
+ const ok = def &&
5285
+ def.arms.length === 2 &&
5286
+ def.arms.some((a) => a.kind === "string") &&
5287
+ def.arms.some((a) => a.kind === "undefinedT");
5288
+ if (!ok) {
5289
+ err(`libCall ${e.fn} must return the 'string | undefined' union`, e.loc);
5290
+ }
5291
+ return true;
5292
+ }
5293
+ if (e.fn === "spawnRes.error") {
5294
+ // Result is the interned `%Error | undefined` union.
5295
+ const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
5296
+ const ok = def &&
5297
+ def.arms.length === 2 &&
5298
+ def.arms.some((a) => a.kind === "object" && a.className === "%Error") &&
5299
+ def.arms.some((a) => a.kind === "undefinedT");
5300
+ if (!ok) {
5301
+ err(`libCall spawnRes.error must return the 'Error | undefined' union`, e.loc);
5302
+ }
5303
+ return true;
5304
+ }
5305
+ if (e.fn === "child.pid" || e.fn === "child.exitCode") {
5306
+ // pid: the interned `number | undefined`; exitCode: `number | null`.
5307
+ const wantUnit = e.fn === "child.pid" ? "undefinedT" : "nullT";
5308
+ const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
5309
+ const ok = def &&
5310
+ def.arms.length === 2 &&
5311
+ def.arms[0].kind === "f64" &&
5312
+ def.arms[1].kind === wantUnit;
5313
+ if (!ok) {
5314
+ err(`libCall ${e.fn} must return the 'number | ${wantUnit === "nullT" ? "null" : "undefined"}' union`, e.loc);
5315
+ }
5316
+ return true;
5317
+ }
5318
+ if (e.fn === "net.serverCloseBind") {
5319
+ // The bound close: (cbUnion) => netServer, cbUnion carrying a
5320
+ // void-returning func arm (≤1 param) and the undefined arm.
5321
+ const t = e.type;
5322
+ const cbU = t.kind === "func" && t.params.length === 1 ? t.params[0] : null;
5323
+ const def = cbU?.kind === "union" ? unions.get(cbU.unionId) : undefined;
5324
+ const ok = t.kind === "func" && (t.ret.kind === "netServer" || t.ret.kind === "void") &&
5325
+ def &&
5326
+ def.arms.some((a) => a.kind === "func" && a.params.length <= 1 && a.ret.kind === "void") &&
5327
+ def.arms.some((a) => a.kind === "undefinedT");
5328
+ if (!ok) {
5329
+ err(`libCall net.serverCloseBind must produce the bound-close func type`, e.loc);
5330
+ }
5331
+ return true;
5332
+ }
5333
+ if (e.fn === "child.stdin" || e.fn === "child.stdout" || e.fn === "child.stderr") {
5334
+ const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
5335
+ const handleKind = e.fn === "child.stdin" ? "childWriter" : "childStream";
5336
+ const ok = def &&
5337
+ def.arms.length === 2 &&
5338
+ def.arms.some((a) => a.kind === handleKind) &&
5339
+ def.arms.some((a) => a.kind === "nullT");
5340
+ if (!ok) {
5341
+ err(`libCall ${e.fn} must return the '${e.fn === "child.stdin" ? "Writable" : "Readable"} | null' union`, e.loc);
5342
+ }
5343
+ return true;
5344
+ }
5345
+ return false;
5346
+ }
5347
+ function checkLibSpecialCall(e) {
5348
+ if (e.fn === "island.castFail") {
5349
+ // The deferred boundary failure's typed dummy: a promise (the
5350
+ // only cast shape the frontend defers).
5351
+ if (e.type.kind !== "promise") {
5352
+ err(`libCall island.castFail must return a promise type, got ${e.type.kind}`, e.loc);
5353
+ }
5354
+ return true;
5355
+ }
5356
+ if (e.fn === "global.undefRead") {
5357
+ // Always throws — the result type is whatever the declared type
5358
+ // of the undefined global mapped to (never materialized).
5359
+ return true;
5360
+ }
5361
+ if (e.fn === "error.nodeThrow" || e.fn === "error.argTypeThrow" || e.fn === "error.propTypeThrow" ||
5362
+ e.fn === "fs.mkdtempChk" || e.fn === "fs.readFileChk" ||
5363
+ e.fn === "fs.opendirChk" || e.fn === "fs.watchFileChk" || e.fn === "fs.lchmodChk" ||
5364
+ e.fn === "fs.readChk" || e.fn === "fs.streamOptsChk" || e.fn === "net.connectOptsChk" ||
5365
+ e.fn === "tls.caCertsChk") {
5366
+ // Always throws — the result type is the replaced expression's
5367
+ // own (never materialized; the global.undefRead pattern). The
5368
+ // fs Chk ladders qualify: every validation failure throws
5369
+ // Node's typed error, and a full pass throws the trailing
5370
+ // compiler-rendered fence.
5371
+ return true;
5372
+ }
5373
+ if (e.fn === "error.new" || e.fn === "error.newOptions") {
5374
+ // Which builtin the runtime constructs is named by the result type.
5375
+ if (!isBuiltinErrorObject(e.type)) {
5376
+ err(`libCall ${e.fn} must return a builtin error class, got ${e.type.kind}`, e.loc);
5377
+ }
5378
+ return true;
5379
+ }
5380
+ if (e.fn === "error.newDom") {
5381
+ if (e.type.kind !== "object" || e.type.className !== "%DOMException") {
5382
+ err(`libCall error.newDom must return %DOMException, got ${e.type.kind}`, e.loc);
5383
+ }
5384
+ return true;
5385
+ }
5386
+ if (e.fn === "error.domCode" || e.fn === "error.domHasCause" || e.fn === "error.domCause" || e.fn === "error.domClone") {
5387
+ // Receiver: exactly %DOMException (subclassing is fenced — the
5388
+ // hidden runtime slots admit no other layout).
5389
+ const recv = e.args[0];
5390
+ if (!recv || recv.type.kind !== "object" || recv.type.className !== "%DOMException") {
5391
+ err(`libCall ${e.fn} receiver must be %DOMException`, e.loc);
5392
+ }
5393
+ return true;
5394
+ }
5395
+ if (e.fn === "class.name") {
5396
+ // The arg is any class value (program-dependent classval).
5397
+ if (e.args[0]?.type.kind !== "classval") {
5398
+ err(`libCall class.name takes a class value`, e.loc);
5399
+ }
5400
+ if (e.type.kind !== "string") {
5401
+ err(`libCall class.name must return string`, e.loc);
5402
+ }
5403
+ return true;
5404
+ }
5405
+ if (e.fn === "assert.refEqBytes" || e.fn === "assert.bytesDeepEq") {
5406
+ // Both value slots: ONE static bytes type (the frontend's
5407
+ // same-static-type gate — a u8/u32 mix would memcmp garbage).
5408
+ const a = e.args[0]?.type;
5409
+ const b = e.args[1]?.type;
5410
+ if (a?.kind !== "bytes" || b === undefined || !typeEquals(a, b)) {
5411
+ err(`libCall ${e.fn} takes two same-typed bytes values`, e.loc);
5412
+ }
5413
+ return true;
5414
+ }
5415
+ if (e.fn === "assert.refEqFn") {
5416
+ // ANY two function signatures: the compare is pointer identity.
5417
+ if (e.args[0]?.type.kind !== "func" || e.args[1]?.type.kind !== "func") {
5418
+ err(`libCall assert.refEqFn takes two function values`, e.loc);
5419
+ }
5420
+ return true;
5421
+ }
5422
+ if (e.fn === "error.code") {
5423
+ // Receiver: any error-hierarchy object (a user subclass embeds
5424
+ // the code slot in its prefix); result: the interned
5425
+ // `string | undefined` union (the process.envGet pattern).
5426
+ const recv = e.args[0];
5427
+ if (!recv || recv.type.kind !== "object") {
5428
+ err(`libCall error.code receiver must be an error object`, e.loc);
5429
+ return true;
5430
+ }
5431
+ const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
5432
+ const ok = def &&
5433
+ def.arms.length === 2 &&
5434
+ def.arms[0].kind === "string" &&
5435
+ def.arms[1].kind === "undefinedT";
5436
+ if (!ok) {
5437
+ err(`libCall error.code must return the 'string | undefined' union`, e.loc);
5438
+ }
5439
+ return true;
5440
+ }
5441
+ return false;
5442
+ }
5443
+ function checkLibStreamCall(e, fixedArgs, result) {
5444
+ if (e.fn.startsWith("readable.") || e.fn.startsWith("writable.") ||
5445
+ e.fn.startsWith("duplex.") || e.fn.startsWith("transform.") ||
5446
+ e.fn.startsWith("passthrough.") || e.fn === "stream.destroy" ||
5447
+ e.fn === "stream.destroyErr" || e.fn === "stream.iteratorClose" || e.fn === "stream.prop" ||
5448
+ e.fn === "stream.errored" || e.fn === "stream.finished" ||
5449
+ e.fn === "stream.finishedDyn" || e.fn === "stream.pipeline" ||
5450
+ e.fn === "stream.pipelineDyn") {
5451
+ // Receiver/result: stream-hierarchy objects (a class whose base
5452
+ // chain reaches a runtime stream class). Constructors have no
5453
+ // receiver — their RESULT names the class; chaining forms
5454
+ // return the receiver's static type; pipe returns its
5455
+ // destination's.
5456
+ const isStreamObject = (t) => {
5457
+ if (t?.kind !== "object")
5458
+ return false;
5459
+ let name = t.className;
5460
+ while (name !== undefined) {
5461
+ if (RUNTIME_STREAM_CLASSES.has(name))
5462
+ return true;
5463
+ name = classes.get(name)?.base;
5464
+ }
5465
+ return false;
5466
+ };
5467
+ if (e.fn.endsWith(".new")) {
5468
+ if (!isStreamObject(e.type)) {
5469
+ err(`libCall ${e.fn} must return a stream class, got ${e.type.kind}`, e.loc);
5470
+ }
5471
+ for (let i = fixedArgs; i < e.args.length; i++) {
5472
+ if (e.args[i].type.kind !== "func") {
5473
+ err(`libCall ${e.fn} option callback ${i} must be a func`, e.loc);
4692
5474
  }
4693
- break;
4694
5475
  }
4695
- if (e.fn === "sp.get") {
4696
- // Result is the interned `string | null` union (the runtime
4697
- // answers +1-or-NULL; the backend builds the arms).
4698
- const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4699
- const ok = def &&
4700
- def.arms.length === 2 &&
4701
- def.arms.some((a) => a.kind === "string") &&
4702
- def.arms.some((a) => a.kind === "nullT");
4703
- if (!ok) {
4704
- err(`libCall sp.get must return the 'string | null' union`, e.loc);
4705
- }
4706
- break;
5476
+ return true;
5477
+ }
5478
+ if (e.fn.endsWith(".newDyn")) {
5479
+ // The dyn-options constructor: (optsDyn) → the stream class.
5480
+ if (!isStreamObject(e.type)) {
5481
+ err(`libCall ${e.fn} must return a stream class, got ${e.type.kind}`, e.loc);
4707
5482
  }
4708
- if (e.fn === "sp.fromPairs") {
4709
- const t = e.args[0]?.type;
4710
- const ok = t && t.kind === "array" && t.elem.kind === "array" && t.elem.elem.kind === "string";
4711
- if (!ok) {
4712
- err(`libCall sp.fromPairs arg 0: expected string[][], got ${t?.kind}`, e.loc);
4713
- }
4714
- break;
5483
+ return true;
5484
+ }
5485
+ if (e.fn.endsWith(".initDyn")) {
5486
+ // (recv, optsDyn, flags, ...fallback wrapper closures).
5487
+ if (!isStreamObject(e.args[0]?.type)) {
5488
+ err(`libCall ${e.fn} receiver must be a stream-hierarchy object`, e.loc);
4715
5489
  }
4716
- if (e.fn === "sym.desc" || e.fn === "sym.keyFor") {
4717
- // Result is the interned `string | undefined` union (the
4718
- // runtime answers +1-or-NULL; the backend builds the arms).
4719
- const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4720
- const ok = def &&
4721
- def.arms.length === 2 &&
4722
- def.arms.some((a) => a.kind === "string") &&
4723
- def.arms.some((a) => a.kind === "undefinedT");
4724
- if (!ok) {
4725
- err(`libCall ${e.fn} must return the 'string | undefined' union`, e.loc);
5490
+ for (let i = fixedArgs; i < e.args.length; i++) {
5491
+ if (e.args[i].type.kind !== "func") {
5492
+ err(`libCall ${e.fn} fallback callback ${i} must be a func`, e.loc);
4726
5493
  }
4727
- break;
4728
5494
  }
4729
- if (e.fn === "spawnRes.error") {
4730
- // Result is the interned `%Error | undefined` union.
4731
- const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4732
- const ok = def &&
4733
- def.arms.length === 2 &&
4734
- def.arms.some((a) => a.kind === "object" && a.className === "%Error") &&
4735
- def.arms.some((a) => a.kind === "undefinedT");
4736
- if (!ok) {
4737
- err(`libCall spawnRes.error must return the 'Error | undefined' union`, e.loc);
4738
- }
4739
- break;
5495
+ if (e.type.kind !== "void")
5496
+ err(`libCall ${e.fn} must be void`, e.loc);
5497
+ return true;
5498
+ }
5499
+ if (e.fn === "stream.finished" || e.fn === "stream.finishedDyn") {
5500
+ // (recv, cb) → the cleanup closure.
5501
+ if (!isStreamObject(e.args[0]?.type)) {
5502
+ err(`libCall ${e.fn} receiver must be a stream-hierarchy object`, e.loc);
4740
5503
  }
4741
- if (e.fn === "child.pid" || e.fn === "child.exitCode") {
4742
- // pid: the interned `number | undefined`; exitCode: `number | null`.
4743
- const wantUnit = e.fn === "child.pid" ? "undefinedT" : "nullT";
4744
- const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4745
- const ok = def &&
4746
- def.arms.length === 2 &&
4747
- def.arms[0].kind === "f64" &&
4748
- def.arms[1].kind === wantUnit;
4749
- if (!ok) {
4750
- err(`libCall ${e.fn} must return the 'number | ${wantUnit === "nullT" ? "null" : "undefined"}' union`, e.loc);
4751
- }
4752
- break;
5504
+ const cbK = e.args[1]?.type.kind;
5505
+ if (e.fn === "stream.finished" ? cbK !== "func" : cbK !== "dyn") {
5506
+ err(`libCall ${e.fn} callback must be ${e.fn === "stream.finished" ? "a func" : "dyn"}`, e.loc);
4753
5507
  }
4754
- if (e.fn === "net.serverCloseBind") {
4755
- // The bound close: (cbUnion) => netServer, cbUnion carrying a
4756
- // void-returning func arm (≤1 param) and the undefined arm.
4757
- const t = e.type;
4758
- const cbU = t.kind === "func" && t.params.length === 1 ? t.params[0] : null;
4759
- const def = cbU?.kind === "union" ? unions.get(cbU.unionId) : undefined;
4760
- const ok = t.kind === "func" && (t.ret.kind === "netServer" || t.ret.kind === "void") &&
4761
- def &&
4762
- def.arms.some((a) => a.kind === "func" && a.params.length <= 1 && a.ret.kind === "void") &&
4763
- def.arms.some((a) => a.kind === "undefinedT");
4764
- if (!ok) {
4765
- err(`libCall net.serverCloseBind must produce the bound-close func type`, e.loc);
4766
- }
4767
- break;
5508
+ if (e.type.kind !== "func") {
5509
+ err(`libCall ${e.fn} must return the cleanup closure, got ${e.type.kind}`, e.loc);
4768
5510
  }
4769
- if (e.fn === "child.stdin" || e.fn === "child.stdout" || e.fn === "child.stderr") {
4770
- const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4771
- const handleKind = e.fn === "child.stdin" ? "childWriter" : "childStream";
4772
- const ok = def &&
4773
- def.arms.length === 2 &&
4774
- def.arms.some((a) => a.kind === handleKind) &&
4775
- def.arms.some((a) => a.kind === "nullT");
4776
- if (!ok) {
4777
- err(`libCall ${e.fn} must return the '${e.fn === "child.stdin" ? "Writable" : "Readable"} | null' union`, e.loc);
4778
- }
4779
- break;
5511
+ return true;
5512
+ }
5513
+ if (e.fn === "stream.pipeline" || e.fn === "stream.pipelineDyn") {
5514
+ // (count, s1..sn, cb) → the destination's type.
5515
+ const count = e.args[0];
5516
+ const n = count?.kind === "numLit" ? count.value : -1;
5517
+ if (n < 2 || e.args.length !== n + 2) {
5518
+ err(`libCall ${e.fn} count/arity mismatch`, e.loc);
5519
+ return true;
4780
5520
  }
4781
- if (e.fn === "island.castFail") {
4782
- // The deferred boundary failure's typed dummy: a promise (the
4783
- // only cast shape the frontend defers).
4784
- if (e.type.kind !== "promise") {
4785
- err(`libCall island.castFail must return a promise type, got ${e.type.kind}`, e.loc);
5521
+ for (let i = 1; i <= n; i++) {
5522
+ if (!isStreamObject(e.args[i]?.type)) {
5523
+ err(`libCall ${e.fn} stage ${i} must be a stream-hierarchy object`, e.loc);
4786
5524
  }
4787
- break;
4788
5525
  }
4789
- if (e.fn === "global.undefRead") {
4790
- // Always throws — the result type is whatever the declared type
4791
- // of the undefined global mapped to (never materialized).
4792
- break;
5526
+ const cbK = e.args[n + 1]?.type.kind;
5527
+ if (e.fn === "stream.pipeline" ? cbK !== "func" : cbK !== "dyn") {
5528
+ err(`libCall ${e.fn} callback must be ${e.fn === "stream.pipeline" ? "a func" : "dyn"}`, e.loc);
4793
5529
  }
4794
- if (e.fn === "error.nodeThrow" || e.fn === "error.argTypeThrow" || e.fn === "error.propTypeThrow" ||
4795
- e.fn === "fs.mkdtempChk" || e.fn === "fs.readFileChk" ||
4796
- e.fn === "fs.opendirChk" || e.fn === "fs.watchFileChk" || e.fn === "fs.lchmodChk" ||
4797
- e.fn === "fs.readChk" || e.fn === "fs.streamOptsChk" || e.fn === "net.connectOptsChk" ||
4798
- e.fn === "tls.caCertsChk") {
4799
- // Always throws — the result type is the replaced expression's
4800
- // own (never materialized; the global.undefRead pattern). The
4801
- // fs Chk ladders qualify: every validation failure throws
4802
- // Node's typed error, and a full pass throws the trailing
4803
- // compiler-rendered fence.
4804
- break;
5530
+ if (!typeEquals(e.type, e.args[n].type)) {
5531
+ err(`libCall ${e.fn} must return its destination's type`, e.loc);
4805
5532
  }
4806
- if (e.fn === "error.new") {
4807
- // Which builtin the runtime constructs is named by the result type.
4808
- if (!isBuiltinErrorObject(e.type)) {
4809
- err(`libCall error.new must return a builtin error class, got ${e.type.kind}`, e.loc);
4810
- }
4811
- break;
5533
+ return true;
5534
+ }
5535
+ if (e.fn === "readable.fromArr") {
5536
+ // No receiver: the seed array leads; the result is the class.
5537
+ if (e.args[0]?.type.kind !== "array" || !isStreamObject(e.type)) {
5538
+ err(`libCall readable.fromArr must take an array and return a stream class`, e.loc);
4812
5539
  }
4813
- if (e.fn === "error.newDom") {
4814
- if (e.type.kind !== "object" || e.type.className !== "%DOMException") {
4815
- err(`libCall error.newDom must return %DOMException, got ${e.type.kind}`, e.loc);
4816
- }
4817
- break;
5540
+ return true;
5541
+ }
5542
+ if (!isStreamObject(e.args[0]?.type)) {
5543
+ err(`libCall ${e.fn} receiver must be a stream-hierarchy object`, e.loc);
5544
+ return true;
5545
+ }
5546
+ if (e.fn === "readable.nextChunk" || e.fn === "readable.nextChunkDyn") {
5547
+ if (e.type.kind !== "promise") {
5548
+ err(`libCall ${e.fn} must return a promise, got ${e.type.kind}`, e.loc);
4818
5549
  }
4819
- if (e.fn === "error.domCode" || e.fn === "error.domHasCause" || e.fn === "error.domCause" || e.fn === "error.domClone") {
4820
- // Receiver: exactly %DOMException (subclassing is fenced — the
4821
- // hidden runtime slots admit no other layout).
4822
- const recv = e.args[0];
4823
- if (!recv || recv.type.kind !== "object" || recv.type.className !== "%DOMException") {
4824
- err(`libCall ${e.fn} receiver must be %DOMException`, e.loc);
4825
- }
4826
- break;
5550
+ return true;
5551
+ }
5552
+ if (e.fn === "readable.pause" || e.fn === "readable.resume" ||
5553
+ e.fn === "readable.unpipe" || e.fn === "writable.end" ||
5554
+ e.fn === "readable.setEncoding" || e.fn === "readable.pushEncoding" ||
5555
+ e.fn === "stream.destroy" || e.fn === "stream.destroyErr" ||
5556
+ e.fn === "stream.iteratorClose") {
5557
+ if (!typeEquals(e.type, e.args[0].type)) {
5558
+ err(`libCall ${e.fn} must return its receiver's type (the chaining 'this')`, e.loc);
4827
5559
  }
4828
- if (e.fn === "class.name") {
4829
- // The arg is any class value (program-dependent classval).
4830
- if (e.args[0]?.type.kind !== "classval") {
4831
- err(`libCall class.name takes a class value`, e.loc);
4832
- }
4833
- if (e.type.kind !== "string") {
4834
- err(`libCall class.name must return string`, e.loc);
4835
- }
4836
- break;
5560
+ return true;
5561
+ }
5562
+ if (e.fn === "readable.pipe") {
5563
+ if (!isStreamObject(e.args[1]?.type) || !typeEquals(e.type, e.args[1].type)) {
5564
+ err(`libCall readable.pipe must return its destination's type`, e.loc);
4837
5565
  }
4838
- if (e.fn === "assert.refEqBytes" || e.fn === "assert.bytesDeepEq") {
4839
- // Both value slots: ONE static bytes type (the frontend's
4840
- // same-static-type gate — a u8/u32 mix would memcmp garbage).
4841
- const a = e.args[0]?.type;
4842
- const b = e.args[1]?.type;
4843
- if (a?.kind !== "bytes" || b === undefined || !typeEquals(a, b)) {
4844
- err(`libCall ${e.fn} takes two same-typed bytes values`, e.loc);
4845
- }
4846
- break;
5566
+ return true;
5567
+ }
5568
+ if (e.fn === "readable.read" || e.fn === "readable.flowing" || e.fn === "stream.errored") {
5569
+ const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
5570
+ const wantArm = (t) => e.fn === "readable.read" ? t.kind === "bytes" :
5571
+ e.fn === "readable.flowing" ? t.kind === "bool" :
5572
+ t.kind === "object";
5573
+ const ok = def && def.arms.length === 2 &&
5574
+ def.arms.some(wantArm) && def.arms.some((a) => a.kind === "nullT");
5575
+ if (!ok)
5576
+ err(`libCall ${e.fn} must return its nullable union`, e.loc);
5577
+ return true;
5578
+ }
5579
+ if (e.fn === "stream.prop") {
5580
+ if (e.type.kind !== "bool" && e.type.kind !== "f64") {
5581
+ err(`libCall stream.prop must be bool or f64, got ${e.type.kind}`, e.loc);
4847
5582
  }
4848
- if (e.fn === "assert.refEqFn") {
4849
- // ANY two function signatures: the compare is pointer identity.
4850
- if (e.args[0]?.type.kind !== "func" || e.args[1]?.type.kind !== "func") {
4851
- err(`libCall assert.refEqFn takes two function values`, e.loc);
4852
- }
4853
- break;
5583
+ return true;
5584
+ }
5585
+ if (!typeEquals(e.type, result)) {
5586
+ err(`libCall ${e.fn} must be ${result.kind}, got ${e.type.kind}`, e.loc);
5587
+ }
5588
+ return true;
5589
+ }
5590
+ return false;
5591
+ }
5592
+ function checkLibEmitterCall(e, result) {
5593
+ if (e.fn.startsWith("emitter.") && e.fn !== "emitter.setDefaultMax" &&
5594
+ e.fn !== "emitter.setDefaultMaxChk" &&
5595
+ e.fn !== "emitter.getDefaultMax" && e.fn !== "emitter.checkListener") {
5596
+ // Receiver: an emitter-hierarchy object (the %EventEmitter class
5597
+ // itself, or a class whose base chain reaches it). emitter.new
5598
+ // has no receiver — its RESULT is the bare emitter class.
5599
+ const isEmitterObject = (t) => {
5600
+ if (t?.kind !== "object")
5601
+ return false;
5602
+ let name = t.className;
5603
+ while (name !== undefined) {
5604
+ if (name === RUNTIME_EMITTER_CLASS)
5605
+ return true;
5606
+ name = classes.get(name)?.base;
5607
+ }
5608
+ return false;
5609
+ };
5610
+ if (e.fn === "emitter.new") {
5611
+ if (e.type.kind !== "object" || e.type.className !== RUNTIME_EMITTER_CLASS) {
5612
+ err(`libCall emitter.new must return '%EventEmitter', got ${e.type.kind}`, e.loc);
4854
5613
  }
4855
- if (e.fn === "error.code") {
4856
- // Receiver: any error-hierarchy object (a user subclass embeds
4857
- // the code slot in its prefix); result: the interned
4858
- // `string | undefined` union (the process.envGet pattern).
4859
- const recv = e.args[0];
4860
- if (!recv || recv.type.kind !== "object") {
4861
- err(`libCall error.code receiver must be an error object`, e.loc);
4862
- break;
4863
- }
4864
- const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
4865
- const ok = def &&
4866
- def.arms.length === 2 &&
4867
- def.arms[0].kind === "string" &&
4868
- def.arms[1].kind === "undefinedT";
4869
- if (!ok) {
4870
- err(`libCall error.code must return the 'string | undefined' union`, e.loc);
4871
- }
4872
- break;
5614
+ return true;
5615
+ }
5616
+ if (!isEmitterObject(e.args[0]?.type)) {
5617
+ err(`libCall ${e.fn} receiver must be an emitter-hierarchy object`, e.loc);
5618
+ return true;
5619
+ }
5620
+ // The chaining forms return the receiver's own static class.
5621
+ if (e.fn === "emitter.on" || e.fn === "emitter.off" ||
5622
+ e.fn === "emitter.onDyn" || e.fn === "emitter.onFlex" || e.fn === "emitter.offDyn" ||
5623
+ e.fn === "emitter.onData" || e.fn === "emitter.onDataDyn" ||
5624
+ e.fn === "emitter.removeAll" || e.fn === "emitter.setMax" ||
5625
+ e.fn === "emitter.setMaxChk") {
5626
+ if (!typeEquals(e.type, e.args[0].type)) {
5627
+ err(`libCall ${e.fn} must return its receiver's type (the chaining 'this')`, e.loc);
4873
5628
  }
4874
- if (e.fn.startsWith("readable.") || e.fn.startsWith("writable.") ||
4875
- e.fn.startsWith("duplex.") || e.fn.startsWith("transform.") ||
4876
- e.fn.startsWith("passthrough.") || e.fn === "stream.destroy" ||
4877
- e.fn === "stream.destroyErr" || e.fn === "stream.iteratorClose" || e.fn === "stream.prop" ||
4878
- e.fn === "stream.errored" || e.fn === "stream.finished" ||
4879
- e.fn === "stream.finishedDyn" || e.fn === "stream.pipeline" ||
4880
- e.fn === "stream.pipelineDyn") {
4881
- // Receiver/result: stream-hierarchy objects (a class whose base
4882
- // chain reaches a runtime stream class). Constructors have no
4883
- // receiver — their RESULT names the class; chaining forms
4884
- // return the receiver's static type; pipe returns its
4885
- // destination's.
4886
- const isStreamObject = (t) => {
4887
- if (t?.kind !== "object")
4888
- return false;
4889
- let name = t.className;
4890
- while (name !== undefined) {
4891
- if (RUNTIME_STREAM_CLASSES.has(name))
4892
- return true;
4893
- name = classes.get(name)?.base;
4894
- }
4895
- return false;
4896
- };
4897
- if (e.fn.endsWith(".new")) {
4898
- if (!isStreamObject(e.type)) {
4899
- err(`libCall ${e.fn} must return a stream class, got ${e.type.kind}`, e.loc);
4900
- }
4901
- for (let i = sig.argTypes.length; i < e.args.length; i++) {
4902
- if (e.args[i].type.kind !== "func") {
4903
- err(`libCall ${e.fn} option callback ${i} must be a func`, e.loc);
4904
- }
4905
- }
4906
- break;
4907
- }
4908
- if (e.fn.endsWith(".newDyn")) {
4909
- // The dyn-options constructor: (optsDyn) → the stream class.
4910
- if (!isStreamObject(e.type)) {
4911
- err(`libCall ${e.fn} must return a stream class, got ${e.type.kind}`, e.loc);
4912
- }
4913
- break;
4914
- }
4915
- if (e.fn.endsWith(".initDyn")) {
4916
- // (recv, optsDyn, flags, ...fallback wrapper closures).
4917
- if (!isStreamObject(e.args[0]?.type)) {
4918
- err(`libCall ${e.fn} receiver must be a stream-hierarchy object`, e.loc);
4919
- }
4920
- for (let i = sig.argTypes.length; i < e.args.length; i++) {
4921
- if (e.args[i].type.kind !== "func") {
4922
- err(`libCall ${e.fn} fallback callback ${i} must be a func`, e.loc);
4923
- }
4924
- }
4925
- if (e.type.kind !== "void")
4926
- err(`libCall ${e.fn} must be void`, e.loc);
4927
- break;
4928
- }
4929
- if (e.fn === "stream.finished" || e.fn === "stream.finishedDyn") {
4930
- // (recv, cb) → the cleanup closure.
4931
- if (!isStreamObject(e.args[0]?.type)) {
4932
- err(`libCall ${e.fn} receiver must be a stream-hierarchy object`, e.loc);
4933
- }
4934
- const cbK = e.args[1]?.type.kind;
4935
- if (e.fn === "stream.finished" ? cbK !== "func" : cbK !== "dyn") {
4936
- err(`libCall ${e.fn} callback must be ${e.fn === "stream.finished" ? "a func" : "dyn"}`, e.loc);
4937
- }
4938
- if (e.type.kind !== "func") {
4939
- err(`libCall ${e.fn} must return the cleanup closure, got ${e.type.kind}`, e.loc);
4940
- }
4941
- break;
4942
- }
4943
- if (e.fn === "stream.pipeline" || e.fn === "stream.pipelineDyn") {
4944
- // (count, s1..sn, cb) → the destination's type.
4945
- const count = e.args[0];
4946
- const n = count?.kind === "numLit" ? count.value : -1;
4947
- if (n < 2 || e.args.length !== n + 2) {
4948
- err(`libCall ${e.fn} count/arity mismatch`, e.loc);
4949
- break;
4950
- }
4951
- for (let i = 1; i <= n; i++) {
4952
- if (!isStreamObject(e.args[i]?.type)) {
4953
- err(`libCall ${e.fn} stage ${i} must be a stream-hierarchy object`, e.loc);
4954
- }
4955
- }
4956
- const cbK = e.args[n + 1]?.type.kind;
4957
- if (e.fn === "stream.pipeline" ? cbK !== "func" : cbK !== "dyn") {
4958
- err(`libCall ${e.fn} callback must be ${e.fn === "stream.pipeline" ? "a func" : "dyn"}`, e.loc);
4959
- }
4960
- if (!typeEquals(e.type, e.args[n].type)) {
4961
- err(`libCall ${e.fn} must return its destination's type`, e.loc);
4962
- }
4963
- break;
4964
- }
4965
- if (e.fn === "readable.fromArr") {
4966
- // No receiver: the seed array leads; the result is the class.
4967
- if (e.args[0]?.type.kind !== "array" || !isStreamObject(e.type)) {
4968
- err(`libCall readable.fromArr must take an array and return a stream class`, e.loc);
4969
- }
4970
- break;
4971
- }
4972
- if (!isStreamObject(e.args[0]?.type)) {
4973
- err(`libCall ${e.fn} receiver must be a stream-hierarchy object`, e.loc);
4974
- break;
4975
- }
4976
- if (e.fn === "readable.nextChunk" || e.fn === "readable.nextChunkDyn") {
4977
- if (e.type.kind !== "promise") {
4978
- err(`libCall ${e.fn} must return a promise, got ${e.type.kind}`, e.loc);
4979
- }
4980
- break;
4981
- }
4982
- if (e.fn === "readable.pause" || e.fn === "readable.resume" ||
4983
- e.fn === "readable.unpipe" || e.fn === "writable.end" ||
4984
- e.fn === "readable.setEncoding" || e.fn === "readable.pushEncoding" ||
4985
- e.fn === "stream.destroy" || e.fn === "stream.destroyErr" ||
4986
- e.fn === "stream.iteratorClose") {
4987
- if (!typeEquals(e.type, e.args[0].type)) {
4988
- err(`libCall ${e.fn} must return its receiver's type (the chaining 'this')`, e.loc);
4989
- }
4990
- break;
4991
- }
4992
- if (e.fn === "readable.pipe") {
4993
- if (!isStreamObject(e.args[1]?.type) || !typeEquals(e.type, e.args[1].type)) {
4994
- err(`libCall readable.pipe must return its destination's type`, e.loc);
4995
- }
4996
- break;
4997
- }
4998
- if (e.fn === "readable.read" || e.fn === "readable.flowing" || e.fn === "stream.errored") {
4999
- const def = e.type.kind === "union" ? unions.get(e.type.unionId) : undefined;
5000
- const wantArm = (t) => e.fn === "readable.read" ? t.kind === "bytes" :
5001
- e.fn === "readable.flowing" ? t.kind === "bool" :
5002
- t.kind === "object";
5003
- const ok = def && def.arms.length === 2 &&
5004
- def.arms.some(wantArm) && def.arms.some((a) => a.kind === "nullT");
5005
- if (!ok)
5006
- err(`libCall ${e.fn} must return its nullable union`, e.loc);
5007
- break;
5008
- }
5009
- if (e.fn === "stream.prop") {
5010
- if (e.type.kind !== "bool" && e.type.kind !== "f64") {
5011
- err(`libCall stream.prop must be bool or f64, got ${e.type.kind}`, e.loc);
5012
- }
5013
- break;
5014
- }
5015
- if (!typeEquals(e.type, sig.result)) {
5016
- err(`libCall ${e.fn} must be ${sig.result.kind}, got ${e.type.kind}`, e.loc);
5017
- }
5018
- break;
5629
+ // The listener slots carry closures (the dyn family's checked-
5630
+ // dynamic listener is table-checked; its adapter is a func).
5631
+ if ((e.fn === "emitter.on" || e.fn === "emitter.off" || e.fn === "emitter.onData") && e.args[2]?.type.kind !== "func") {
5632
+ err(`libCall ${e.fn} listener must be a func`, e.loc);
5019
5633
  }
5020
- if (e.fn.startsWith("emitter.") && e.fn !== "emitter.setDefaultMax" &&
5021
- e.fn !== "emitter.setDefaultMaxChk" &&
5022
- e.fn !== "emitter.getDefaultMax" && e.fn !== "emitter.checkListener") {
5023
- // Receiver: an emitter-hierarchy object (the %EventEmitter class
5024
- // itself, or a class whose base chain reaches it). emitter.new
5025
- // has no receiver — its RESULT is the bare emitter class.
5026
- const isEmitterObject = (t) => {
5027
- if (t?.kind !== "object")
5028
- return false;
5029
- let name = t.className;
5030
- while (name !== undefined) {
5031
- if (name === RUNTIME_EMITTER_CLASS)
5032
- return true;
5033
- name = classes.get(name)?.base;
5034
- }
5035
- return false;
5036
- };
5037
- if (e.fn === "emitter.new") {
5038
- if (e.type.kind !== "object" || e.type.className !== RUNTIME_EMITTER_CLASS) {
5039
- err(`libCall emitter.new must return '%EventEmitter', got ${e.type.kind}`, e.loc);
5040
- }
5041
- break;
5042
- }
5043
- if (!isEmitterObject(e.args[0]?.type)) {
5044
- err(`libCall ${e.fn} receiver must be an emitter-hierarchy object`, e.loc);
5045
- break;
5046
- }
5047
- // The chaining forms return the receiver's own static class.
5048
- if (e.fn === "emitter.on" || e.fn === "emitter.off" ||
5049
- e.fn === "emitter.onDyn" || e.fn === "emitter.onFlex" || e.fn === "emitter.offDyn" ||
5050
- e.fn === "emitter.onData" || e.fn === "emitter.onDataDyn" ||
5051
- e.fn === "emitter.removeAll" || e.fn === "emitter.setMax" ||
5052
- e.fn === "emitter.setMaxChk") {
5053
- if (!typeEquals(e.type, e.args[0].type)) {
5054
- err(`libCall ${e.fn} must return its receiver's type (the chaining 'this')`, e.loc);
5055
- }
5056
- // The listener slots carry closures (the dyn family's checked-
5057
- // dynamic listener is table-checked; its adapter is a func).
5058
- if ((e.fn === "emitter.on" || e.fn === "emitter.off" || e.fn === "emitter.onData") && e.args[2]?.type.kind !== "func") {
5059
- err(`libCall ${e.fn} listener must be a func`, e.loc);
5060
- }
5061
- if ((e.fn === "emitter.onDyn" || e.fn === "emitter.onDataDyn") && e.args[3]?.type.kind !== "func") {
5062
- err(`libCall ${e.fn} adapter must be a func`, e.loc);
5063
- }
5064
- break;
5065
- }
5066
- if (e.fn === "emitter.emitData") {
5067
- const chunkT = e.args[2]?.type;
5068
- const ok = chunkT !== undefined &&
5069
- ((chunkT.kind === "bytes" && chunkT.elem === "u8") || chunkT.kind === "string");
5070
- if (!ok)
5071
- err(`libCall emitter.emitData chunk must be bytes<u8> or string`, e.loc);
5072
- if (e.type.kind !== "bool")
5073
- err(`libCall emitter.emitData must be bool`, e.loc);
5074
- break;
5075
- }
5076
- if (e.fn === "emitter.countFn" && e.args[2]?.type.kind !== "func") {
5077
- err(`libCall emitter.countFn listener must be a func`, e.loc);
5078
- break;
5079
- }
5080
- if (e.fn === "emitter.emitError" && e.args[2]?.type.kind !== "object") {
5081
- err(`libCall emitter.emitError payload must be an error-hierarchy object`, e.loc);
5082
- break;
5083
- }
5084
- if (e.fn === "emitter.names") {
5085
- const ok = e.type.kind === "array" && e.type.elem.kind === "string";
5086
- if (!ok)
5087
- err(`libCall emitter.names must return string[]`, e.loc);
5088
- break;
5089
- }
5090
- if (e.fn === "emitter.listeners") {
5091
- const ok = e.type.kind === "array" && e.type.elem.kind === "func";
5092
- if (!ok)
5093
- err(`libCall emitter.listeners must return a func array`, e.loc);
5094
- break;
5095
- }
5096
- if (e.fn === "emitter.emitFlex") {
5097
- if (e.args.slice(2).some((arg) => arg.type.kind !== "dyn")) {
5098
- err("libCall emitter.emitFlex payloads must be checked-dynamic", e.loc);
5099
- }
5100
- }
5101
- if (e.fn === "emitter.emit" || e.fn === "emitter.emitFlex" || e.fn === "emitter.count" ||
5102
- e.fn === "emitter.getMax" || e.fn === "emitter.ctor" ||
5103
- e.fn === "emitter.countFn" || e.fn === "emitter.emitError") {
5104
- if (!typeEquals(e.type, sig.result)) {
5105
- err(`libCall ${e.fn} must be ${sig.result.kind}, got ${e.type.kind}`, e.loc);
5106
- }
5107
- break;
5108
- }
5634
+ if ((e.fn === "emitter.onDyn" || e.fn === "emitter.onDataDyn") && e.args[3]?.type.kind !== "func") {
5635
+ err(`libCall ${e.fn} adapter must be a func`, e.loc);
5109
5636
  }
5110
- if (e.fn === "error.ctor" || e.fn === "error.toString") {
5111
- const recv = e.args[0];
5112
- const wantErrorRoot = e.fn === "error.toString";
5113
- const ok = recv &&
5114
- isBuiltinErrorObject(recv.type) &&
5115
- (!wantErrorRoot || (recv.type.kind === "object" && recv.type.className === "%Error"));
5116
- if (!ok) {
5117
- err(`libCall ${e.fn} receiver must be ${wantErrorRoot ? "'%Error'" : "a builtin error class"}`, e.loc);
5118
- }
5637
+ return true;
5638
+ }
5639
+ if (e.fn === "emitter.emitData") {
5640
+ const chunkT = e.args[2]?.type;
5641
+ const ok = chunkT !== undefined &&
5642
+ ((chunkT.kind === "bytes" && chunkT.elem === "u8") || chunkT.kind === "string");
5643
+ if (!ok)
5644
+ err(`libCall emitter.emitData chunk must be bytes<u8> or string`, e.loc);
5645
+ if (e.type.kind !== "bool")
5646
+ err(`libCall emitter.emitData must be bool`, e.loc);
5647
+ return true;
5648
+ }
5649
+ if (e.fn === "emitter.countFn" && e.args[2]?.type.kind !== "func") {
5650
+ err(`libCall emitter.countFn listener must be a func`, e.loc);
5651
+ return true;
5652
+ }
5653
+ if (e.fn === "emitter.emitError" && e.args[2]?.type.kind !== "object") {
5654
+ err(`libCall emitter.emitError payload must be an error-hierarchy object`, e.loc);
5655
+ return true;
5656
+ }
5657
+ if (e.fn === "emitter.names") {
5658
+ const ok = e.type.kind === "array" && e.type.elem.kind === "string";
5659
+ if (!ok)
5660
+ err(`libCall emitter.names must return string[]`, e.loc);
5661
+ return true;
5662
+ }
5663
+ if (e.fn === "emitter.listeners") {
5664
+ const ok = e.type.kind === "array" && e.type.elem.kind === "func";
5665
+ if (!ok)
5666
+ err(`libCall emitter.listeners must return a func array`, e.loc);
5667
+ return true;
5668
+ }
5669
+ if (e.fn === "emitter.emitFlex") {
5670
+ if (e.args.slice(2).some((arg) => arg.type.kind !== "dyn")) {
5671
+ err("libCall emitter.emitFlex payloads must be checked-dynamic", e.loc);
5119
5672
  }
5120
- if (!typeEquals(e.type, sig.result)) {
5121
- err(`libCall ${e.fn} must be ${sig.result.kind}, got ${e.type.kind}`, e.loc);
5673
+ }
5674
+ if (e.fn === "emitter.emit" || e.fn === "emitter.emitFlex" || e.fn === "emitter.count" ||
5675
+ e.fn === "emitter.getMax" || e.fn === "emitter.ctor" ||
5676
+ e.fn === "emitter.countFn" || e.fn === "emitter.countDyn" || e.fn === "emitter.emitError") {
5677
+ if (!typeEquals(e.type, result)) {
5678
+ err(`libCall ${e.fn} must be ${result.kind}, got ${e.type.kind}`, e.loc);
5122
5679
  }
5123
- break;
5680
+ return true;
5124
5681
  }
5682
+ }
5683
+ return false;
5684
+ }
5685
+ function checkConversionExpr(e) {
5686
+ switch (e.kind) {
5125
5687
  case "jsonStringify": {
5126
5688
  checkExpr(e.value);
5127
5689
  if (e.type.kind !== "string") {
@@ -5166,11 +5728,19 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
5166
5728
  // Runtime HANDLE targets unwrap the checked-dynamic tree's handle kind by tag (a
5167
5729
  // retained reference, no copy — DYN_HANDLE_KINDS).
5168
5730
  const handleOk = DYN_HANDLE_KINDS.has(e.type.kind);
5169
- if (!jsonOk(e.type) && !undefArmedOk && !bytesOk && !errorOk && !classOk && !funcOk && !handleOk) {
5731
+ if (!canDynCheckTo(e.type, (id) => records.get(id), (id) => unions.get(id)) && !undefArmedOk && !bytesOk && !errorOk && !classOk && !funcOk && !handleOk) {
5170
5732
  err(`dynCheck against non-JSON-representable type ${e.type.kind}`, e.loc);
5171
5733
  }
5172
5734
  break;
5173
5735
  }
5736
+ default: {
5737
+ const _exhaustive = e;
5738
+ void _exhaustive;
5739
+ }
5740
+ }
5741
+ }
5742
+ function checkAsyncExpr(e) {
5743
+ switch (e.kind) {
5174
5744
  case "awaitExpr": {
5175
5745
  checkExpr(e.value);
5176
5746
  if (e.value.type.kind !== "promise") {
@@ -5198,7 +5768,12 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
5198
5768
  }
5199
5769
  // The undefined next-channel has no C value form: such yields are
5200
5770
  // void-typed (statement position only — the frontend fences reads).
5201
- if (fn.generator.nextT.kind === "undefinedT") {
5771
+ if (e.captureCompletion) {
5772
+ if (fn.async || e.type.kind !== "dyn" || !typeEquals(e.captureCompletion.returnType, fn.returnType)) {
5773
+ err("invalid captured generator completion", e.loc);
5774
+ }
5775
+ }
5776
+ else if (fn.generator.nextT.kind === "undefinedT") {
5202
5777
  if (e.type.kind !== "void")
5203
5778
  err("yield result must be void on an undefined next-channel", e.loc);
5204
5779
  }
@@ -5239,7 +5814,6 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
5239
5814
  err("genResume throw with no payload", e.loc);
5240
5815
  }
5241
5816
  else if (e.arg.type.kind === "void" ||
5242
- e.arg.type.kind === "dyn" ||
5243
5817
  e.arg.type.kind === "caught" ||
5244
5818
  e.arg.type.kind === "date") {
5245
5819
  err(`genResume throw of a ${e.arg.type.kind} value`, e.loc);
@@ -5377,6 +5951,14 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
5377
5951
  }
5378
5952
  break;
5379
5953
  }
5954
+ default: {
5955
+ const _exhaustive = e;
5956
+ void _exhaustive;
5957
+ }
5958
+ }
5959
+ }
5960
+ function checkIslandExpr(e) {
5961
+ switch (e.kind) {
5380
5962
  case "jsMarshal": {
5381
5963
  checkExpr(e.value);
5382
5964
  if (e.type.kind !== "jsval")
@@ -5530,6 +6112,9 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
5530
6112
  }
5531
6113
  case "assign": {
5532
6114
  const binding = locals.get(s.localId) ?? globals.get(s.localId);
6115
+ if (s.initializes && !binding?.tdz) {
6116
+ err(`initializing assign requires a TDZ binding "${s.localId}"`, s.loc);
6117
+ }
5533
6118
  if (!binding)
5534
6119
  err(`assign to undeclared local/global "${s.localId}"`, s.loc);
5535
6120
  // Global initialization happens via assign inside %init functions,
@@ -5538,7 +6123,7 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
5538
6123
  // emits the init-time one. Locals keep the strict check — except a
5539
6124
  // TDZ const, whose source declaration IS an assign into the
5540
6125
  // scope-entry box (tsc rejects user reassignment there too).
5541
- else if (!binding.mutable && locals.has(s.localId) && !("tdz" in binding && binding.tdz)) {
6126
+ else if (!binding.mutable && locals.has(s.localId) && !locals.get(s.localId)?.tdz) {
5542
6127
  err(`assign to immutable local "${binding.name}"`, s.loc);
5543
6128
  }
5544
6129
  if (binding?.type.kind === "caught") {
@@ -5849,138 +6434,4 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
5849
6434
  err(`non-void function may complete without returning`, fn.loc);
5850
6435
  }
5851
6436
  }
5852
- /** Conservative "all paths return" — mirrors what tsc already guarantees. */
5853
- function alwaysReturns(stmts, unions) {
5854
- for (const s of stmts) {
5855
- switch (s.kind) {
5856
- case "return":
5857
- return true;
5858
- case "throw":
5859
- case "rethrow":
5860
- case "runtimeFence":
5861
- // Terminates the path like return: control unwinds (to a handler or
5862
- // out of the function), never falling off the end. tsc agrees —
5863
- // `function f(): T { throw x; }` typechecks without a return.
5864
- return true;
5865
- case "exprStmt":
5866
- // process.exit never returns (fflush + _Exit): the path terminates
5867
- // like a throw. Mirrors tsc's own never-based reachability, which
5868
- // accepted the function without a trailing return — the
5869
- // parseAsync().catch entry handler ends exactly this way.
5870
- if (s.expr.kind === "libCall" && s.expr.fn === "process.exit")
5871
- return true;
5872
- break;
5873
- case "tryCatch":
5874
- // Normal completion requires the try body to complete normally (and
5875
- // the catch, when the try raised) — if both always terminate, so
5876
- // does the whole statement. Without a catch, an exception keeps
5877
- // propagating (never a normal completion), so the try body alone
5878
- // decides. A finally that always terminates (throw) also decides.
5879
- if (alwaysReturns(s.tryBody, unions) &&
5880
- (s.catchBody === null || alwaysReturns(s.catchBody, unions))) {
5881
- return true;
5882
- }
5883
- if (s.finallyBody && alwaysReturns(s.finallyBody, unions))
5884
- return true;
5885
- break;
5886
- case "if":
5887
- if (s.else_ && alwaysReturns(s.then, unions) && alwaysReturns(s.else_, unions))
5888
- return true;
5889
- break;
5890
- case "while":
5891
- // `while (true)` with no break never completes normally (tsc treats
5892
- // it the same way), so anything after it is unreachable.
5893
- if (s.cond.kind === "boolLit" && s.cond.value && !containsBreak(s.body))
5894
- return true;
5895
- break;
5896
- case "for":
5897
- // `for (;;)` — no condition, or a literal-true one — with no break
5898
- // never completes normally either (the walk-up-until-root idiom:
5899
- // every exit is a return).
5900
- if ((s.cond === null || (s.cond.kind === "boolLit" && s.cond.value)) &&
5901
- !containsBreak(s.body)) {
5902
- return true;
5903
- }
5904
- break;
5905
- case "block":
5906
- if (alwaysReturns(s.body, unions))
5907
- return true;
5908
- break;
5909
- case "doWhile":
5910
- // The body runs at least once: if it returns on all paths, so does
5911
- // the loop. `do {} while (true)` with no break never completes.
5912
- if (alwaysReturns(s.body, unions))
5913
- return true;
5914
- if (s.cond.kind === "boolLit" && s.cond.value && !containsBreak(s.body))
5915
- return true;
5916
- break;
5917
- case "switch": {
5918
- // A switch always returns when no case body ever breaks out, every
5919
- // possible entry point (any case) reaches a return, and dispatch
5920
- // cannot miss every case: either a default exists, or the switch is
5921
- // an EXHAUSTIVE discriminant switch — the discriminant is a
5922
- // `unionDisc` over a union with N arms, every test is a distinct
5923
- // literal, and there are at least N of them. (At least: several
5924
- // discriminant VALUES can share one deduped IR arm, e.g.
5925
- // `{op: 0; a} | {op: 2; a}` is one record shape.) The real
5926
- // exhaustiveness guarantee is tsc's — it accepted the function
5927
- // without a trailing return (trust-the-checker, like narrowing
5928
- // itself); this condition only keeps hand-written IR conservative.
5929
- // With no switch-level breaks, execution from case i runs bodies
5930
- // i..end as a straight line — check that flattened suffix.
5931
- const hasDefault = s.cases.some((c) => c.test === null);
5932
- const literalTests = s.cases.map((c) => c.test).filter((t) => t !== null && (t.kind === "numLit" || t.kind === "strLit" || t.kind === "boolLit"));
5933
- const distinct = new Set(literalTests.map((t) => `${t.kind}:${String(t.value)}`));
5934
- const exhaustive = !hasDefault &&
5935
- s.disc.kind === "unionDisc" &&
5936
- literalTests.length === s.cases.length &&
5937
- distinct.size === s.cases.length &&
5938
- s.cases.length >= (unions.get(s.disc.unionId)?.arms.length ?? Infinity);
5939
- if (!hasDefault && !exhaustive)
5940
- break;
5941
- if (s.cases.some((c) => containsBreak(c.body)))
5942
- break;
5943
- const bodies = s.cases.map((c) => c.body);
5944
- const everyEntryReturns = bodies.every((_, i) => alwaysReturns(bodies.slice(i).flat(), unions));
5945
- if (everyEntryReturns)
5946
- return true;
5947
- break;
5948
- }
5949
- default:
5950
- break;
5951
- }
5952
- }
5953
- return false;
5954
- }
5955
- /** Break at this level (not inside a nested loop or switch, whose bodies
5956
- * own their breaks). */
5957
- function containsBreak(stmts) {
5958
- for (const s of stmts) {
5959
- switch (s.kind) {
5960
- case "break":
5961
- return true;
5962
- case "if":
5963
- if (containsBreak(s.then) || (s.else_ && containsBreak(s.else_)))
5964
- return true;
5965
- break;
5966
- case "block":
5967
- if (containsBreak(s.body))
5968
- return true;
5969
- break;
5970
- case "tryCatch":
5971
- // Plain try/catch does not capture breaks — a break inside binds to
5972
- // the enclosing loop/switch (finally-crossing jumps are rejected
5973
- // upstream, so reachable IR only has these in plain try/catch).
5974
- if (containsBreak(s.tryBody) ||
5975
- (s.catchBody !== null && containsBreak(s.catchBody)) ||
5976
- (s.finallyBody !== null && containsBreak(s.finallyBody))) {
5977
- return true;
5978
- }
5979
- break;
5980
- default:
5981
- break; // while/for/doWhile/switch bodies own their breaks
5982
- }
5983
- }
5984
- return false;
5985
- }
5986
6437
  //# sourceMappingURL=validate.js.map