@scriptc/compiler 0.1.7 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1043) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +98 -39
  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 +108 -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 +88 -30
  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 +21 -2
  65. package/dist/backend/llvm/dyn.js +647 -251
  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 +769 -425
  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 +2 -2
  76. package/dist/backend/llvm/expr-bytes.js +60 -31
  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 +10 -6
  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 +78 -81
  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 +62 -31
  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 +54 -7
  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 +220 -131
  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 +44 -19
  138. package/dist/backend/llvm/lib-process.js.map +1 -1
  139. package/dist/backend/llvm/lib-shared.js +162 -3
  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 +42 -131
  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 +12 -30
  183. package/dist/backend/native-toolchain.js +83 -233
  184. package/dist/backend/native-toolchain.js.map +1 -1
  185. package/dist/backend/native-toolchain.test.js +77 -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 +73 -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 +103 -34
  216. package/dist/backend/targets.js.map +1 -1
  217. package/dist/backend/targets.test.js +72 -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 +37 -7
  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 +5 -10
  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 +74 -0
  345. package/dist/frontend/lowering/class-callbacks.js.map +1 -0
  346. package/dist/frontend/lowering/class-construction.d.ts +12 -0
  347. package/dist/frontend/lowering/class-construction.js +156 -0
  348. package/dist/frontend/lowering/class-construction.js.map +1 -0
  349. package/dist/frontend/lowering/class-descriptors.d.ts +10 -0
  350. package/dist/frontend/lowering/class-descriptors.js +114 -0
  351. package/dist/frontend/lowering/class-descriptors.js.map +1 -0
  352. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +51 -0
  353. package/dist/frontend/lowering/class-dynamic-dispatch.js +1158 -0
  354. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -0
  355. package/dist/frontend/lowering/class-dynamic-dispatch.test.d.ts +1 -0
  356. package/dist/frontend/lowering/class-dynamic-dispatch.test.js +93 -0
  357. package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -0
  358. package/dist/frontend/lowering/class-instance-constructor.d.ts +7 -0
  359. package/dist/frontend/lowering/class-instance-constructor.js +67 -0
  360. package/dist/frontend/lowering/class-instance-constructor.js.map +1 -0
  361. package/dist/frontend/lowering/class-method-values.d.ts +13 -0
  362. package/dist/frontend/lowering/class-method-values.js +235 -0
  363. package/dist/frontend/lowering/class-method-values.js.map +1 -0
  364. package/dist/frontend/lowering/class-prototypes.d.ts +19 -0
  365. package/dist/frontend/lowering/class-prototypes.js +242 -0
  366. package/dist/frontend/lowering/class-prototypes.js.map +1 -0
  367. package/dist/frontend/lowering/class-runtime-statics.d.ts +8 -0
  368. package/dist/frontend/lowering/class-runtime-statics.js +66 -0
  369. package/dist/frontend/lowering/class-runtime-statics.js.map +1 -0
  370. package/dist/frontend/lowering/class-static-data.d.ts +6 -0
  371. package/dist/frontend/lowering/class-static-data.js +56 -0
  372. package/dist/frontend/lowering/class-static-data.js.map +1 -0
  373. package/dist/frontend/lowering/containers/buffer-numeric-methods.d.ts +4 -0
  374. package/dist/frontend/lowering/containers/buffer-numeric-methods.js +26 -0
  375. package/dist/frontend/lowering/containers/buffer-numeric-methods.js.map +1 -0
  376. package/dist/frontend/lowering/containers/bytes.d.ts +11 -7
  377. package/dist/frontend/lowering/containers/bytes.js +208 -163
  378. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  379. package/dist/frontend/lowering/containers/string-and-regexp.d.ts +2 -2
  380. package/dist/frontend/lowering/containers/string-and-regexp.js +58 -63
  381. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  382. package/dist/frontend/lowering/containers/string-replacement.d.ts +7 -0
  383. package/dist/frontend/lowering/containers/string-replacement.js +217 -0
  384. package/dist/frontend/lowering/containers/string-replacement.js.map +1 -0
  385. package/dist/frontend/lowering/error-methods.d.ts +14 -0
  386. package/dist/frontend/lowering/error-methods.js +177 -0
  387. package/dist/frontend/lowering/error-methods.js.map +1 -0
  388. package/dist/frontend/lowering/expressions/global-symbols.d.ts +6 -0
  389. package/dist/frontend/lowering/expressions/global-symbols.js +11 -0
  390. package/dist/frontend/lowering/expressions/global-symbols.js.map +1 -0
  391. package/dist/frontend/lowering/expressions/native-proxy.d.ts +7 -0
  392. package/dist/frontend/lowering/expressions/native-proxy.js +51 -0
  393. package/dist/frontend/lowering/expressions/native-proxy.js.map +1 -0
  394. package/dist/frontend/lowering/expressions/nullish-assignment.d.ts +6 -0
  395. package/dist/frontend/lowering/expressions/nullish-assignment.js +132 -0
  396. package/dist/frontend/lowering/expressions/nullish-assignment.js.map +1 -0
  397. package/dist/frontend/lowering/expressions/object-literals.d.ts +8 -8
  398. package/dist/frontend/lowering/expressions/object-literals.js +509 -183
  399. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  400. package/dist/frontend/lowering/expressions/optional-chains.d.ts +3 -4
  401. package/dist/frontend/lowering/expressions/optional-chains.js +88 -24
  402. package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
  403. package/dist/frontend/lowering/expressions/try-lower-expression.js +1 -0
  404. package/dist/frontend/lowering/expressions/try-lower-expression.js.map +1 -1
  405. package/dist/frontend/lowering/expressions/union-field-write.d.ts +8 -0
  406. package/dist/frontend/lowering/expressions/union-field-write.js +71 -0
  407. package/dist/frontend/lowering/expressions/union-field-write.js.map +1 -0
  408. package/dist/frontend/lowering/function-context.d.ts +101 -0
  409. package/dist/frontend/lowering/function-context.js +109 -0
  410. package/dist/frontend/lowering/function-context.js.map +1 -0
  411. package/dist/frontend/lowering/generator-delegation.d.ts +7 -0
  412. package/dist/frontend/lowering/generator-delegation.js +85 -0
  413. package/dist/frontend/lowering/generator-delegation.js.map +1 -0
  414. package/dist/frontend/lowering/generator-dynamic-dispatch.d.ts +11 -0
  415. package/dist/frontend/lowering/generator-dynamic-dispatch.js +143 -0
  416. package/dist/frontend/lowering/generator-dynamic-dispatch.js.map +1 -0
  417. package/dist/frontend/lowering/lib-boundary.d.ts +4 -1
  418. package/dist/frontend/lowering/lib-boundary.js +112 -20
  419. package/dist/frontend/lowering/lib-boundary.js.map +1 -1
  420. package/dist/frontend/lowering/lib-boundary.test.d.ts +1 -0
  421. package/dist/frontend/lowering/lib-boundary.test.js +45 -0
  422. package/dist/frontend/lowering/lib-boundary.test.js.map +1 -0
  423. package/dist/frontend/lowering/lower-array-sort.d.ts +1 -1
  424. package/dist/frontend/lowering/lower-assert.d.ts +1 -1
  425. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  426. package/dist/frontend/lowering/lower-async-iteration.d.ts +1 -1
  427. package/dist/frontend/lowering/lower-async-iteration.js.map +1 -1
  428. package/dist/frontend/lowering/lower-builtin-values.d.ts +18 -0
  429. package/dist/frontend/lowering/lower-builtin-values.js +249 -0
  430. package/dist/frontend/lowering/lower-builtin-values.js.map +1 -0
  431. package/dist/frontend/lowering/lower-builtins.d.ts +33 -46
  432. package/dist/frontend/lowering/lower-builtins.js +676 -365
  433. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  434. package/dist/frontend/lowering/lower-calls.d.ts +28 -22
  435. package/dist/frontend/lowering/lower-calls.js +1660 -412
  436. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  437. package/dist/frontend/lowering/lower-classes.d.ts +95 -57
  438. package/dist/frontend/lowering/lower-classes.js +1491 -404
  439. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  440. package/dist/frontend/lowering/lower-comptime.d.ts +1 -1
  441. package/dist/frontend/lowering/lower-comptime.js +23 -32
  442. package/dist/frontend/lowering/lower-comptime.js.map +1 -1
  443. package/dist/frontend/lowering/lower-containers.d.ts +36 -32
  444. package/dist/frontend/lowering/lower-containers.js +925 -181
  445. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  446. package/dist/frontend/lowering/lower-dgram.d.ts +1 -1
  447. package/dist/frontend/lowering/lower-dgram.js +3 -2
  448. package/dist/frontend/lowering/lower-dgram.js.map +1 -1
  449. package/dist/frontend/lowering/lower-enums.d.ts +1 -1
  450. package/dist/frontend/lowering/lower-enums.js.map +1 -1
  451. package/dist/frontend/lowering/lower-event-emitter.d.ts +30 -1
  452. package/dist/frontend/lowering/lower-event-emitter.js +58 -26
  453. package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
  454. package/dist/frontend/lowering/lower-expando.d.ts +7 -1
  455. package/dist/frontend/lowering/lower-expando.js +14 -6
  456. package/dist/frontend/lowering/lower-expando.js.map +1 -1
  457. package/dist/frontend/lowering/lower-exprs.d.ts +37 -13
  458. package/dist/frontend/lowering/lower-exprs.js +2163 -863
  459. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  460. package/dist/frontend/lowering/lower-generators.d.ts +2 -5
  461. package/dist/frontend/lowering/lower-generators.js +88 -46
  462. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  463. package/dist/frontend/lowering/lower-global-value.d.ts +7 -0
  464. package/dist/frontend/lowering/lower-global-value.js +17 -0
  465. package/dist/frontend/lowering/lower-global-value.js.map +1 -0
  466. package/dist/frontend/lowering/lower-inspect.d.ts +1 -1
  467. package/dist/frontend/lowering/lower-inspect.js +17 -8
  468. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  469. package/dist/frontend/lowering/lower-island.d.ts +7 -8
  470. package/dist/frontend/lowering/lower-island.js +66 -33
  471. package/dist/frontend/lowering/lower-island.js.map +1 -1
  472. package/dist/frontend/lowering/lower-mixins.d.ts +2 -2
  473. package/dist/frontend/lowering/lower-mixins.js +5 -3
  474. package/dist/frontend/lowering/lower-mixins.js.map +1 -1
  475. package/dist/frontend/lowering/lower-modules.d.ts +1 -1
  476. package/dist/frontend/lowering/lower-modules.js +445 -39
  477. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  478. package/dist/frontend/lowering/lower-modules.test.d.ts +1 -0
  479. package/dist/frontend/lowering/lower-modules.test.js +39 -0
  480. package/dist/frontend/lowering/lower-modules.test.js.map +1 -0
  481. package/dist/frontend/lowering/lower-namespaces.d.ts +1 -1
  482. package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
  483. package/dist/frontend/lowering/lower-node-module.d.ts +1 -1
  484. package/dist/frontend/lowering/lower-node-module.js +13 -10
  485. package/dist/frontend/lowering/lower-node-module.js.map +1 -1
  486. package/dist/frontend/lowering/lower-server.d.ts +1 -1
  487. package/dist/frontend/lowering/lower-server.js +6 -10
  488. package/dist/frontend/lowering/lower-server.js.map +1 -1
  489. package/dist/frontend/lowering/lower-stmts.d.ts +17 -17
  490. package/dist/frontend/lowering/lower-stmts.js +855 -514
  491. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  492. package/dist/frontend/lowering/lower-stream.d.ts +1 -1
  493. package/dist/frontend/lowering/lower-stream.js +20 -11
  494. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  495. package/dist/frontend/lowering/lower-test.d.ts +1 -1
  496. package/dist/frontend/lowering/lower-test.js.map +1 -1
  497. package/dist/frontend/lowering/lower-url.d.ts +6 -0
  498. package/dist/frontend/lowering/lower-url.js +77 -0
  499. package/dist/frontend/lowering/lower-url.js.map +1 -0
  500. package/dist/frontend/lowering/lowerer.d.ts +140 -190
  501. package/dist/frontend/lowering/lowerer.js +1193 -712
  502. package/dist/frontend/lowering/lowerer.js.map +1 -1
  503. package/dist/frontend/lowering/lowerer.test.d.ts +1 -0
  504. package/dist/frontend/lowering/lowerer.test.js +172 -0
  505. package/dist/frontend/lowering/lowerer.test.js.map +1 -0
  506. package/dist/frontend/lowering/native-ffi.d.ts +5 -0
  507. package/dist/frontend/lowering/native-ffi.js +40 -0
  508. package/dist/frontend/lowering/native-ffi.js.map +1 -0
  509. package/dist/frontend/lowering/object-enumeration-receiver.d.ts +7 -0
  510. package/dist/frontend/lowering/object-enumeration-receiver.js +33 -0
  511. package/dist/frontend/lowering/object-enumeration-receiver.js.map +1 -0
  512. package/dist/frontend/lowering/object-factory-new.d.ts +8 -0
  513. package/dist/frontend/lowering/object-factory-new.js +68 -0
  514. package/dist/frontend/lowering/object-factory-new.js.map +1 -0
  515. package/dist/frontend/lowering/optional-arguments.js +6 -1
  516. package/dist/frontend/lowering/optional-arguments.js.map +1 -1
  517. package/dist/frontend/lowering/pairs-snapshot.js +2 -1
  518. package/dist/frontend/lowering/pairs-snapshot.js.map +1 -1
  519. package/dist/frontend/lowering/runtime-optional-locals.d.ts +14 -0
  520. package/dist/frontend/lowering/runtime-optional-locals.js +41 -0
  521. package/dist/frontend/lowering/runtime-optional-locals.js.map +1 -0
  522. package/dist/frontend/lowering/runtime-optional-locals.test.d.ts +1 -0
  523. package/dist/frontend/lowering/runtime-optional-locals.test.js +85 -0
  524. package/dist/frontend/lowering/runtime-optional-locals.test.js.map +1 -0
  525. package/dist/frontend/lowering/sanitize-class-types.d.ts +8 -0
  526. package/dist/frontend/lowering/sanitize-class-types.js +79 -0
  527. package/dist/frontend/lowering/sanitize-class-types.js.map +1 -0
  528. package/dist/frontend/lowering/sanitize-class-types.test.d.ts +1 -0
  529. package/dist/frontend/lowering/sanitize-class-types.test.js +60 -0
  530. package/dist/frontend/lowering/sanitize-class-types.test.js.map +1 -0
  531. package/dist/frontend/lowering/static-this.d.ts +5 -1
  532. package/dist/frontend/lowering/static-this.js +28 -2
  533. package/dist/frontend/lowering/static-this.js.map +1 -1
  534. package/dist/frontend/lowering/string-index.d.ts +7 -0
  535. package/dist/frontend/lowering/string-index.js +39 -0
  536. package/dist/frontend/lowering/string-index.js.map +1 -0
  537. package/dist/frontend/lowering/surfaces.d.ts +10 -3
  538. package/dist/frontend/lowering/surfaces.js +86 -37
  539. package/dist/frontend/lowering/surfaces.js.map +1 -1
  540. package/dist/frontend/lowering/symbol-fields.d.ts +22 -0
  541. package/dist/frontend/lowering/symbol-fields.js +183 -0
  542. package/dist/frontend/lowering/symbol-fields.js.map +1 -0
  543. package/dist/frontend/lowering/symbol-methods.d.ts +7 -0
  544. package/dist/frontend/lowering/symbol-methods.js +30 -0
  545. package/dist/frontend/lowering/symbol-methods.js.map +1 -0
  546. package/dist/frontend/lowering/text-decoder-encoding.d.ts +12 -0
  547. package/dist/frontend/lowering/text-decoder-encoding.js +82 -0
  548. package/dist/frontend/lowering/text-decoder-encoding.js.map +1 -0
  549. package/dist/frontend/lowering/text-decoder-encoding.test.d.ts +1 -0
  550. package/dist/frontend/lowering/text-decoder-encoding.test.js +38 -0
  551. package/dist/frontend/lowering/text-decoder-encoding.test.js.map +1 -0
  552. package/dist/frontend/lowering/union-narrow.d.ts +9 -0
  553. package/dist/frontend/lowering/union-narrow.js +59 -0
  554. package/dist/frontend/lowering/union-narrow.js.map +1 -0
  555. package/dist/frontend/lowering/union-narrow.test.d.ts +1 -0
  556. package/dist/frontend/lowering/union-narrow.test.js +72 -0
  557. package/dist/frontend/lowering/union-narrow.test.js.map +1 -0
  558. package/dist/frontend/lowering/union-retag.d.ts +43 -0
  559. package/dist/frontend/lowering/union-retag.js +259 -0
  560. package/dist/frontend/lowering/union-retag.js.map +1 -0
  561. package/dist/frontend/lowering/union-retag.test.d.ts +1 -0
  562. package/dist/frontend/lowering/union-retag.test.js +405 -0
  563. package/dist/frontend/lowering/union-retag.test.js.map +1 -0
  564. package/dist/frontend/lowering/unregistered-class-types.d.ts +14 -0
  565. package/dist/frontend/lowering/unregistered-class-types.js +94 -0
  566. package/dist/frontend/lowering/unregistered-class-types.js.map +1 -0
  567. package/dist/frontend/lowering/unregistered-class-types.test.d.ts +1 -0
  568. package/dist/frontend/lowering/unregistered-class-types.test.js +65 -0
  569. package/dist/frontend/lowering/unregistered-class-types.test.js.map +1 -0
  570. package/dist/frontend/lowering/width-lift.d.ts +40 -0
  571. package/dist/frontend/lowering/width-lift.js +2 -0
  572. package/dist/frontend/lowering/width-lift.js.map +1 -0
  573. package/dist/frontend/module-syntax.d.ts +58 -0
  574. package/dist/frontend/module-syntax.js +123 -0
  575. package/dist/frontend/module-syntax.js.map +1 -0
  576. package/dist/frontend/module-syntax.test.d.ts +1 -0
  577. package/dist/frontend/module-syntax.test.js +78 -0
  578. package/dist/frontend/module-syntax.test.js.map +1 -0
  579. package/dist/frontend/npm-fetch-analysis.d.ts +17 -0
  580. package/dist/frontend/npm-fetch-analysis.js +100 -0
  581. package/dist/frontend/npm-fetch-analysis.js.map +1 -0
  582. package/dist/frontend/npm-fetch-analysis.test.d.ts +1 -0
  583. package/dist/frontend/npm-fetch-analysis.test.js +107 -0
  584. package/dist/frontend/npm-fetch-analysis.test.js.map +1 -0
  585. package/dist/frontend/npm-fetch-node.d.ts +2 -0
  586. package/dist/frontend/npm-fetch-node.js +12 -0
  587. package/dist/frontend/npm-fetch-node.js.map +1 -0
  588. package/dist/frontend/npm-fetch-syntax.d.ts +6 -0
  589. package/dist/frontend/npm-fetch-syntax.js +207 -0
  590. package/dist/frontend/npm-fetch-syntax.js.map +1 -0
  591. package/dist/frontend/npm-node.d.ts +10 -0
  592. package/dist/frontend/npm-node.js +14 -0
  593. package/dist/frontend/npm-node.js.map +1 -0
  594. package/dist/frontend/npm-static-bundled-cjs.d.ts +8 -0
  595. package/dist/frontend/npm-static-bundled-cjs.js +236 -0
  596. package/dist/frontend/npm-static-bundled-cjs.js.map +1 -0
  597. package/dist/frontend/npm-static-bundled-cjs.test.d.ts +1 -0
  598. package/dist/frontend/npm-static-bundled-cjs.test.js +69 -0
  599. package/dist/frontend/npm-static-bundled-cjs.test.js.map +1 -0
  600. package/dist/frontend/npm-static-declaration-syntax.d.ts +57 -0
  601. package/dist/frontend/npm-static-declaration-syntax.js +944 -0
  602. package/dist/frontend/npm-static-declaration-syntax.js.map +1 -0
  603. package/dist/frontend/npm-static-declarations.d.ts +11 -39
  604. package/dist/frontend/npm-static-declarations.js +22 -561
  605. package/dist/frontend/npm-static-declarations.js.map +1 -1
  606. package/dist/frontend/npm-static-declarations.test.js +245 -6
  607. package/dist/frontend/npm-static-declarations.test.js.map +1 -1
  608. package/dist/frontend/npm-static-prune.d.ts +1 -1
  609. package/dist/frontend/npm-static-prune.js +121 -38
  610. package/dist/frontend/npm-static-prune.js.map +1 -1
  611. package/dist/frontend/npm-static-prune.test.js +9 -1
  612. package/dist/frontend/npm-static-prune.test.js.map +1 -1
  613. package/dist/frontend/npm-static-rewrite-host.d.ts +4 -0
  614. package/dist/frontend/npm-static-rewrite-host.js +179 -0
  615. package/dist/frontend/npm-static-rewrite-host.js.map +1 -0
  616. package/dist/frontend/npm-static-rewrite-syntax.d.ts +16 -0
  617. package/dist/frontend/npm-static-rewrite-syntax.js +905 -0
  618. package/dist/frontend/npm-static-rewrite-syntax.js.map +1 -0
  619. package/dist/frontend/npm-static-rewrite.d.ts +0 -5
  620. package/dist/frontend/npm-static-rewrite.js +2 -1079
  621. package/dist/frontend/npm-static-rewrite.js.map +1 -1
  622. package/dist/frontend/npm-static-subtyping.d.ts +5 -0
  623. package/dist/frontend/npm-static-subtyping.js +55 -0
  624. package/dist/frontend/npm-static-subtyping.js.map +1 -0
  625. package/dist/frontend/npm-static-subtyping.test.d.ts +1 -0
  626. package/dist/frontend/npm-static-subtyping.test.js +58 -0
  627. package/dist/frontend/npm-static-subtyping.test.js.map +1 -0
  628. package/dist/frontend/npm-static.d.ts +7 -15
  629. package/dist/frontend/npm-static.js +19 -28
  630. package/dist/frontend/npm-static.js.map +1 -1
  631. package/dist/frontend/npm.d.ts +8 -69
  632. package/dist/frontend/npm.js +21 -361
  633. package/dist/frontend/npm.js.map +1 -1
  634. package/dist/frontend/npm.test.js +2 -2
  635. package/dist/frontend/npm.test.js.map +1 -1
  636. package/dist/frontend/pipeline-native.d.ts +6 -0
  637. package/dist/frontend/pipeline-native.js +32 -0
  638. package/dist/frontend/pipeline-native.js.map +1 -0
  639. package/dist/frontend/pipeline.d.ts +54 -0
  640. package/dist/frontend/pipeline.js +382 -0
  641. package/dist/frontend/pipeline.js.map +1 -0
  642. package/dist/frontend/pipeline.test.d.ts +1 -0
  643. package/dist/frontend/pipeline.test.js +77 -0
  644. package/dist/frontend/pipeline.test.js.map +1 -0
  645. package/dist/frontend/program-analysis.d.ts +10 -0
  646. package/dist/frontend/program-analysis.js +14 -0
  647. package/dist/frontend/program-analysis.js.map +1 -0
  648. package/dist/frontend/program-node.d.ts +9 -0
  649. package/dist/frontend/program-node.js +48 -0
  650. package/dist/frontend/program-node.js.map +1 -0
  651. package/dist/frontend/program.d.ts +39 -20
  652. package/dist/frontend/program.js +393 -189
  653. package/dist/frontend/program.js.map +1 -1
  654. package/dist/frontend/program.test.js +105 -2
  655. package/dist/frontend/program.test.js.map +1 -1
  656. package/dist/frontend/provenance-core.d.ts +9 -0
  657. package/dist/frontend/provenance-core.js +435 -0
  658. package/dist/frontend/provenance-core.js.map +1 -0
  659. package/dist/frontend/provenance.d.ts +0 -4
  660. package/dist/frontend/provenance.js +4 -459
  661. package/dist/frontend/provenance.js.map +1 -1
  662. package/dist/frontend/resolve.d.ts +3 -1
  663. package/dist/frontend/resolve.js +6 -3
  664. package/dist/frontend/resolve.js.map +1 -1
  665. package/dist/frontend/runtime-resolve.d.ts +4 -3
  666. package/dist/frontend/runtime-resolve.js +22 -18
  667. package/dist/frontend/runtime-resolve.js.map +1 -1
  668. package/dist/frontend/runtime-resolve.test.js +53 -0
  669. package/dist/frontend/runtime-resolve.test.js.map +1 -1
  670. package/dist/frontend/services-node.d.ts +5 -0
  671. package/dist/frontend/services-node.js +19 -0
  672. package/dist/frontend/services-node.js.map +1 -0
  673. package/dist/frontend/services-node.test.d.ts +1 -0
  674. package/dist/frontend/services-node.test.js +70 -0
  675. package/dist/frontend/services-node.test.js.map +1 -0
  676. package/dist/frontend/services.d.ts +44 -0
  677. package/dist/frontend/services.js +90 -0
  678. package/dist/frontend/services.js.map +1 -0
  679. package/dist/frontend/services.test.d.ts +1 -0
  680. package/dist/frontend/services.test.js +174 -0
  681. package/dist/frontend/services.test.js.map +1 -0
  682. package/dist/frontend/ts7/adapter.d.ts +3 -3
  683. package/dist/frontend/ts7/adapter.js +14 -31
  684. package/dist/frontend/ts7/adapter.js.map +1 -1
  685. package/dist/frontend/ts7/api.d.ts +16 -0
  686. package/dist/frontend/ts7/api.js +24 -0
  687. package/dist/frontend/ts7/api.js.map +1 -0
  688. package/dist/frontend/ts7/ast-bytes.d.ts +31 -0
  689. package/dist/frontend/ts7/ast-bytes.js +137 -0
  690. package/dist/frontend/ts7/ast-bytes.js.map +1 -0
  691. package/dist/frontend/ts7/ast-bytes.test.d.ts +1 -0
  692. package/dist/frontend/ts7/ast-bytes.test.js +73 -0
  693. package/dist/frontend/ts7/ast-bytes.test.js.map +1 -0
  694. package/dist/frontend/ts7/ast-guards.generated.d.ts +353 -0
  695. package/dist/frontend/ts7/ast-guards.generated.js +1951 -0
  696. package/dist/frontend/ts7/ast-guards.generated.js.map +1 -0
  697. package/dist/frontend/ts7/ast-guards.test.d.ts +1 -0
  698. package/dist/frontend/ts7/ast-guards.test.js +43 -0
  699. package/dist/frontend/ts7/ast-guards.test.js.map +1 -0
  700. package/dist/frontend/ts7/ast-node.d.ts +194 -0
  701. package/dist/frontend/ts7/ast-node.js +448 -0
  702. package/dist/frontend/ts7/ast-node.js.map +1 -0
  703. package/dist/frontend/ts7/ast-node.test.d.ts +1 -0
  704. package/dist/frontend/ts7/ast-node.test.js +266 -0
  705. package/dist/frontend/ts7/ast-node.test.js.map +1 -0
  706. package/dist/frontend/ts7/ast-schema.generated.d.ts +503 -0
  707. package/dist/frontend/ts7/ast-schema.generated.js +1446 -0
  708. package/dist/frontend/ts7/ast-schema.generated.js.map +1 -0
  709. package/dist/frontend/ts7/ast-text.d.ts +6 -0
  710. package/dist/frontend/ts7/ast-text.js +124 -0
  711. package/dist/frontend/ts7/ast-text.js.map +1 -0
  712. package/dist/frontend/ts7/ast-text.test.d.ts +1 -0
  713. package/dist/frontend/ts7/ast-text.test.js +38 -0
  714. package/dist/frontend/ts7/ast-text.test.js.map +1 -0
  715. package/dist/frontend/ts7/ast-tokens.generated.d.ts +2 -0
  716. package/dist/frontend/ts7/ast-tokens.generated.js +155 -0
  717. package/dist/frontend/ts7/ast-tokens.generated.js.map +1 -0
  718. package/dist/frontend/ts7/ast-types.d.ts +42 -0
  719. package/dist/frontend/ts7/ast-types.generated.d.ts +1615 -0
  720. package/dist/frontend/ts7/ast-types.generated.js +5 -0
  721. package/dist/frontend/ts7/ast-types.generated.js.map +1 -0
  722. package/dist/frontend/ts7/ast-types.js +3 -0
  723. package/dist/frontend/ts7/ast-types.js.map +1 -0
  724. package/dist/frontend/ts7/ast-wire.d.ts +58 -0
  725. package/dist/frontend/ts7/ast-wire.js +267 -0
  726. package/dist/frontend/ts7/ast-wire.js.map +1 -0
  727. package/dist/frontend/ts7/ast-wire.test.d.ts +1 -0
  728. package/dist/frontend/ts7/ast-wire.test.js +151 -0
  729. package/dist/frontend/ts7/ast-wire.test.js.map +1 -0
  730. package/dist/frontend/ts7/ast.d.ts +14 -14
  731. package/dist/frontend/ts7/ast.js +25 -18
  732. package/dist/frontend/ts7/ast.js.map +1 -1
  733. package/dist/frontend/ts7/census-check.js +1 -0
  734. package/dist/frontend/ts7/census-check.js.map +1 -1
  735. package/dist/frontend/ts7/checker-cache.d.ts +48 -0
  736. package/dist/frontend/ts7/checker-cache.js +92 -0
  737. package/dist/frontend/ts7/checker-cache.js.map +1 -0
  738. package/dist/frontend/ts7/checker.d.ts +19 -46
  739. package/dist/frontend/ts7/checker.js +231 -161
  740. package/dist/frontend/ts7/checker.js.map +1 -1
  741. package/dist/frontend/ts7/checker.test.d.ts +1 -0
  742. package/dist/frontend/ts7/checker.test.js +335 -0
  743. package/dist/frontend/ts7/checker.test.js.map +1 -0
  744. package/dist/frontend/ts7/enums.d.ts +4 -27
  745. package/dist/frontend/ts7/enums.generated.d.ts +878 -0
  746. package/dist/frontend/ts7/enums.generated.js +1313 -0
  747. package/dist/frontend/ts7/enums.generated.js.map +1 -0
  748. package/dist/frontend/ts7/enums.js +4 -45
  749. package/dist/frontend/ts7/enums.js.map +1 -1
  750. package/dist/frontend/ts7/enums.test.d.ts +1 -0
  751. package/dist/frontend/ts7/enums.test.js +48 -0
  752. package/dist/frontend/ts7/enums.test.js.map +1 -0
  753. package/dist/frontend/ts7/native-api.d.ts +10 -0
  754. package/dist/frontend/ts7/native-api.js +10 -0
  755. package/dist/frontend/ts7/native-api.js.map +1 -0
  756. package/dist/frontend/ts7/native-host.d.ts +2 -0
  757. package/dist/frontend/ts7/native-host.js +11 -0
  758. package/dist/frontend/ts7/native-host.js.map +1 -0
  759. package/dist/frontend/ts7/native-process.d.ts +14 -0
  760. package/dist/frontend/ts7/native-process.js +62 -0
  761. package/dist/frontend/ts7/native-process.js.map +1 -0
  762. package/dist/frontend/ts7/program-adapter.d.ts +10 -98
  763. package/dist/frontend/ts7/program-adapter.js +16 -310
  764. package/dist/frontend/ts7/program-adapter.js.map +1 -1
  765. package/dist/frontend/ts7/program-host.d.ts +115 -0
  766. package/dist/frontend/ts7/program-host.js +347 -0
  767. package/dist/frontend/ts7/program-host.js.map +1 -0
  768. package/dist/frontend/ts7/program-host.test.d.ts +1 -0
  769. package/dist/frontend/ts7/program-host.test.js +207 -0
  770. package/dist/frontend/ts7/program-host.test.js.map +1 -0
  771. package/dist/frontend/ts7/rpc-api.d.ts +12 -0
  772. package/dist/frontend/ts7/rpc-api.js +23 -0
  773. package/dist/frontend/ts7/rpc-api.js.map +1 -0
  774. package/dist/frontend/ts7/rpc-client.d.ts +27 -0
  775. package/dist/frontend/ts7/rpc-client.js +102 -0
  776. package/dist/frontend/ts7/rpc-client.js.map +1 -0
  777. package/dist/frontend/ts7/rpc-client.test.d.ts +1 -0
  778. package/dist/frontend/ts7/rpc-client.test.js +133 -0
  779. package/dist/frontend/ts7/rpc-client.test.js.map +1 -0
  780. package/dist/frontend/ts7/rpc-filesystem.d.ts +16 -0
  781. package/dist/frontend/ts7/rpc-filesystem.js +42 -0
  782. package/dist/frontend/ts7/rpc-filesystem.js.map +1 -0
  783. package/dist/frontend/ts7/rpc-filesystem.test.d.ts +1 -0
  784. package/dist/frontend/ts7/rpc-filesystem.test.js +89 -0
  785. package/dist/frontend/ts7/rpc-filesystem.test.js.map +1 -0
  786. package/dist/frontend/ts7/rpc-process.d.ts +2 -0
  787. package/dist/frontend/ts7/rpc-process.js +148 -0
  788. package/dist/frontend/ts7/rpc-process.js.map +1 -0
  789. package/dist/frontend/ts7/rpc-process.test.d.ts +1 -0
  790. package/dist/frontend/ts7/rpc-process.test.js +29 -0
  791. package/dist/frontend/ts7/rpc-process.test.js.map +1 -0
  792. package/dist/frontend/ts7/rpc-wire.d.ts +46 -0
  793. package/dist/frontend/ts7/rpc-wire.js +195 -0
  794. package/dist/frontend/ts7/rpc-wire.js.map +1 -0
  795. package/dist/frontend/ts7/rpc-wire.test.d.ts +1 -0
  796. package/dist/frontend/ts7/rpc-wire.test.js +168 -0
  797. package/dist/frontend/ts7/rpc-wire.test.js.map +1 -0
  798. package/dist/frontend/ts7/semantic-checker.d.ts +137 -0
  799. package/dist/frontend/ts7/semantic-checker.js +221 -0
  800. package/dist/frontend/ts7/semantic-checker.js.map +1 -0
  801. package/dist/frontend/ts7/semantic-checker.test.d.ts +1 -0
  802. package/dist/frontend/ts7/semantic-checker.test.js +119 -0
  803. package/dist/frontend/ts7/semantic-checker.test.js.map +1 -0
  804. package/dist/frontend/ts7/semantic-json.d.ts +5 -0
  805. package/dist/frontend/ts7/semantic-json.js +47 -0
  806. package/dist/frontend/ts7/semantic-json.js.map +1 -0
  807. package/dist/frontend/ts7/semantic-json.test.d.ts +1 -0
  808. package/dist/frontend/ts7/semantic-json.test.js +42 -0
  809. package/dist/frontend/ts7/semantic-json.test.js.map +1 -0
  810. package/dist/frontend/ts7/semantic-model.d.ts +222 -0
  811. package/dist/frontend/ts7/semantic-model.js +423 -0
  812. package/dist/frontend/ts7/semantic-model.js.map +1 -0
  813. package/dist/frontend/ts7/semantic-model.test.d.ts +1 -0
  814. package/dist/frontend/ts7/semantic-model.test.js +322 -0
  815. package/dist/frontend/ts7/semantic-model.test.js.map +1 -0
  816. package/dist/frontend/ts7/semantic-schema.generated.d.ts +283 -0
  817. package/dist/frontend/ts7/semantic-schema.generated.js +222 -0
  818. package/dist/frontend/ts7/semantic-schema.generated.js.map +1 -0
  819. package/dist/frontend/ts7/semantic-types.d.ts +5 -0
  820. package/dist/frontend/ts7/semantic-types.js +2 -0
  821. package/dist/frontend/ts7/semantic-types.js.map +1 -0
  822. package/dist/frontend/ts7/session-cache.d.ts +17 -0
  823. package/dist/frontend/ts7/session-cache.js +97 -0
  824. package/dist/frontend/ts7/session-cache.js.map +1 -0
  825. package/dist/frontend/ts7/session-cache.test.d.ts +1 -0
  826. package/dist/frontend/ts7/session-cache.test.js +87 -0
  827. package/dist/frontend/ts7/session-cache.test.js.map +1 -0
  828. package/dist/frontend/ts7/session-path.d.ts +18 -0
  829. package/dist/frontend/ts7/session-path.js +203 -0
  830. package/dist/frontend/ts7/session-path.js.map +1 -0
  831. package/dist/frontend/ts7/session-path.test.d.ts +1 -0
  832. package/dist/frontend/ts7/session-path.test.js +34 -0
  833. package/dist/frontend/ts7/session-path.test.js.map +1 -0
  834. package/dist/frontend/ts7/session-schema.generated.d.ts +167 -0
  835. package/dist/frontend/ts7/session-schema.generated.js +5 -0
  836. package/dist/frontend/ts7/session-schema.generated.js.map +1 -0
  837. package/dist/frontend/ts7/session-timing.d.ts +50 -0
  838. package/dist/frontend/ts7/session-timing.js +61 -0
  839. package/dist/frontend/ts7/session-timing.js.map +1 -0
  840. package/dist/frontend/ts7/session-timing.test.d.ts +1 -0
  841. package/dist/frontend/ts7/session-timing.test.js +52 -0
  842. package/dist/frontend/ts7/session-timing.test.js.map +1 -0
  843. package/dist/frontend/ts7/session.d.ts +105 -0
  844. package/dist/frontend/ts7/session.js +233 -0
  845. package/dist/frontend/ts7/session.js.map +1 -0
  846. package/dist/frontend/ts7/session.test.d.ts +1 -0
  847. package/dist/frontend/ts7/session.test.js +215 -0
  848. package/dist/frontend/ts7/session.test.js.map +1 -0
  849. package/dist/frontend/ts7/source-parser-node.d.ts +6 -0
  850. package/dist/frontend/ts7/source-parser-node.js +15 -0
  851. package/dist/frontend/ts7/source-parser-node.js.map +1 -0
  852. package/dist/frontend/ts7/source-parser.d.ts +25 -0
  853. package/dist/frontend/ts7/source-parser.js +96 -0
  854. package/dist/frontend/ts7/source-parser.js.map +1 -0
  855. package/dist/frontend/ts7/source-parser.test.d.ts +1 -0
  856. package/dist/frontend/ts7/source-parser.test.js +151 -0
  857. package/dist/frontend/ts7/source-parser.test.js.map +1 -0
  858. package/dist/frontend/ts7/syntax.d.ts +3 -0
  859. package/dist/frontend/ts7/syntax.js +4 -0
  860. package/dist/frontend/ts7/syntax.js.map +1 -0
  861. package/dist/frontend/tsc-codes.js +3 -0
  862. package/dist/frontend/tsc-codes.js.map +1 -1
  863. package/dist/frontend/type-mapper.d.ts +34 -18
  864. package/dist/frontend/type-mapper.js +552 -131
  865. package/dist/frontend/type-mapper.js.map +1 -1
  866. package/dist/frontend/type-mapper.test.js +146 -2
  867. package/dist/frontend/type-mapper.test.js.map +1 -1
  868. package/dist/frontend/union-discriminants.d.ts +16 -0
  869. package/dist/frontend/union-discriminants.js +98 -0
  870. package/dist/frontend/union-discriminants.js.map +1 -0
  871. package/dist/frontend/union-discriminants.test.d.ts +1 -0
  872. package/dist/frontend/union-discriminants.test.js +182 -0
  873. package/dist/frontend/union-discriminants.test.js.map +1 -0
  874. package/dist/index.d.ts +7 -198
  875. package/dist/index.js +369 -1572
  876. package/dist/index.js.map +1 -1
  877. package/dist/ir/analysis.d.ts +16 -4
  878. package/dist/ir/analysis.js +23 -4
  879. package/dist/ir/analysis.js.map +1 -1
  880. package/dist/ir/analysis.test.js +15 -2
  881. package/dist/ir/analysis.test.js.map +1 -1
  882. package/dist/ir/constant-tables.js +67 -49
  883. package/dist/ir/constant-tables.js.map +1 -1
  884. package/dist/ir/constant-tables.test.js +1 -1
  885. package/dist/ir/control-flow.d.ts +6 -0
  886. package/dist/ir/control-flow.js +142 -0
  887. package/dist/ir/control-flow.js.map +1 -0
  888. package/dist/ir/control-flow.test.d.ts +1 -0
  889. package/dist/ir/control-flow.test.js +113 -0
  890. package/dist/ir/control-flow.test.js.map +1 -0
  891. package/dist/ir/integer-loops.js +7 -18
  892. package/dist/ir/integer-loops.js.map +1 -1
  893. package/dist/ir/integer-ranges.js +53 -27
  894. package/dist/ir/integer-ranges.js.map +1 -1
  895. package/dist/ir/ir.d.ts +334 -176
  896. package/dist/ir/ir.js +710 -903
  897. package/dist/ir/ir.js.map +1 -1
  898. package/dist/ir/ir.test.js +162 -1
  899. package/dist/ir/ir.test.js.map +1 -1
  900. package/dist/ir/scalar-records.js +165 -134
  901. package/dist/ir/scalar-records.js.map +1 -1
  902. package/dist/ir/scalar-records.test.js +1 -1
  903. package/dist/ir/serialize.d.ts +4 -2
  904. package/dist/ir/serialize.js +33 -14
  905. package/dist/ir/serialize.js.map +1 -1
  906. package/dist/ir/serialize.test.d.ts +1 -0
  907. package/dist/ir/serialize.test.js +57 -0
  908. package/dist/ir/serialize.test.js.map +1 -0
  909. package/dist/ir/traverse.d.ts +41 -0
  910. package/dist/ir/traverse.js +660 -0
  911. package/dist/ir/traverse.js.map +1 -0
  912. package/dist/ir/traverse.test.d.ts +1 -0
  913. package/dist/ir/traverse.test.js +242 -0
  914. package/dist/ir/traverse.test.js.map +1 -0
  915. package/dist/ir/validate.js +2018 -1498
  916. package/dist/ir/validate.js.map +1 -1
  917. package/dist/ir/validate.test.js +536 -2
  918. package/dist/ir/validate.test.js.map +1 -1
  919. package/dist/library/cache-primitives.d.ts +2 -3
  920. package/dist/library/cache-primitives.js +4 -6
  921. package/dist/library/cache-primitives.js.map +1 -1
  922. package/dist/library/fence-eval.js +2 -2
  923. package/dist/library/fence-eval.js.map +1 -1
  924. package/dist/library/int-infer.js +7 -6
  925. package/dist/library/int-infer.js.map +1 -1
  926. package/dist/library/int-infer.test.js +4 -4
  927. package/dist/library/library-cache.d.ts +3 -2
  928. package/dist/library/library-cache.js +5 -17
  929. package/dist/library/library-cache.js.map +1 -1
  930. package/dist/library/library-cache.test.js +54 -41
  931. package/dist/library/library-cache.test.js.map +1 -1
  932. package/dist/library/library-profile.d.ts +3 -1
  933. package/dist/library/library-profile.js +15 -6
  934. package/dist/library/library-profile.js.map +1 -1
  935. package/dist/library/prepare.d.ts +15 -0
  936. package/dist/library/prepare.js +584 -0
  937. package/dist/library/prepare.js.map +1 -0
  938. package/dist/library/semantic-source.d.ts +1 -1
  939. package/dist/library/semantic-source.js +8 -6
  940. package/dist/library/semantic-source.js.map +1 -1
  941. package/dist/library/sidecar-validate.js +4 -4
  942. package/dist/library/sidecar-validate.js.map +1 -1
  943. package/dist/library/sidecar.d.ts +2 -0
  944. package/dist/library/sidecar.js +10 -3
  945. package/dist/library/sidecar.js.map +1 -1
  946. package/dist/native/cache.d.ts +11 -0
  947. package/dist/native/cache.js +113 -0
  948. package/dist/native/cache.js.map +1 -0
  949. package/dist/native/cache.test.d.ts +1 -0
  950. package/dist/native/cache.test.js +66 -0
  951. package/dist/native/cache.test.js.map +1 -0
  952. package/dist/native/cli.d.ts +1 -0
  953. package/dist/native/cli.js +112 -0
  954. package/dist/native/cli.js.map +1 -0
  955. package/dist/native/compiler.d.ts +15 -0
  956. package/dist/native/compiler.js +336 -0
  957. package/dist/native/compiler.js.map +1 -0
  958. package/dist/native/compiler.test.d.ts +1 -0
  959. package/dist/native/compiler.test.js +174 -0
  960. package/dist/native/compiler.test.js.map +1 -0
  961. package/dist/native/comptime.d.ts +5 -0
  962. package/dist/native/comptime.js +73 -0
  963. package/dist/native/comptime.js.map +1 -0
  964. package/dist/native/comptime.test.d.ts +1 -0
  965. package/dist/native/comptime.test.js +65 -0
  966. package/dist/native/comptime.test.js.map +1 -0
  967. package/dist/native/executable-cache.d.ts +26 -0
  968. package/dist/native/executable-cache.js +228 -0
  969. package/dist/native/executable-cache.js.map +1 -0
  970. package/dist/native/executable-cache.test.d.ts +1 -0
  971. package/dist/native/executable-cache.test.js +151 -0
  972. package/dist/native/executable-cache.test.js.map +1 -0
  973. package/dist/native/file-identity.d.ts +4 -0
  974. package/dist/native/file-identity.js +14 -0
  975. package/dist/native/file-identity.js.map +1 -0
  976. package/dist/native/file-identity.test.d.ts +1 -0
  977. package/dist/native/file-identity.test.js +43 -0
  978. package/dist/native/file-identity.test.js.map +1 -0
  979. package/dist/native/library.d.ts +22 -0
  980. package/dist/native/library.js +83 -0
  981. package/dist/native/library.js.map +1 -0
  982. package/dist/native/prepare.d.ts +21 -0
  983. package/dist/native/prepare.js +174 -0
  984. package/dist/native/prepare.js.map +1 -0
  985. package/dist/native/prepare.test.d.ts +1 -0
  986. package/dist/native/prepare.test.js +70 -0
  987. package/dist/native/prepare.test.js.map +1 -0
  988. package/dist/native/sanitizer.d.ts +11 -0
  989. package/dist/native/sanitizer.js +137 -0
  990. package/dist/native/sanitizer.js.map +1 -0
  991. package/dist/native/sanitizer.test.d.ts +1 -0
  992. package/dist/native/sanitizer.test.js +58 -0
  993. package/dist/native/sanitizer.test.js.map +1 -0
  994. package/dist/native/task.d.ts +4 -0
  995. package/dist/native/task.js +16 -0
  996. package/dist/native/task.js.map +1 -0
  997. package/dist/native/task.test.d.ts +1 -0
  998. package/dist/native/task.test.js +17 -0
  999. package/dist/native/task.test.js.map +1 -0
  1000. package/dist/native/toolchain.d.ts +45 -0
  1001. package/dist/native/toolchain.js +94 -0
  1002. package/dist/native/toolchain.js.map +1 -0
  1003. package/dist/native/toolchain.test.d.ts +1 -0
  1004. package/dist/native/toolchain.test.js +85 -0
  1005. package/dist/native/toolchain.test.js.map +1 -0
  1006. package/dist/startup-cache.d.ts +1 -1
  1007. package/dist/startup-cache.js +2 -5
  1008. package/dist/startup-cache.js.map +1 -1
  1009. package/dist/timing.d.ts +4 -0
  1010. package/dist/timing.js +19 -0
  1011. package/dist/timing.js.map +1 -0
  1012. package/dist/wasi-paths.js +10 -7
  1013. package/dist/wasi-paths.js.map +1 -1
  1014. package/package.json +28 -19
  1015. package/surface-manifest.json +107 -98
  1016. package/dist/backend/c/async.d.ts +0 -171
  1017. package/dist/backend/c/async.js +0 -1317
  1018. package/dist/backend/c/async.js.map +0 -1
  1019. package/dist/backend/c/c-emitter.d.ts +0 -536
  1020. package/dist/backend/c/c-emitter.js +0 -1932
  1021. package/dist/backend/c/c-emitter.js.map +0 -1
  1022. package/dist/backend/c/exprs.d.ts +0 -15
  1023. package/dist/backend/c/exprs.js +0 -8847
  1024. package/dist/backend/c/exprs.js.map +0 -1
  1025. package/dist/backend/c/island.d.ts +0 -45
  1026. package/dist/backend/c/island.js +0 -281
  1027. package/dist/backend/c/island.js.map +0 -1
  1028. package/dist/backend/c/may-throw.js.map +0 -1
  1029. package/dist/backend/c/shapes.d.ts +0 -142
  1030. package/dist/backend/c/shapes.js +0 -603
  1031. package/dist/backend/c/shapes.js.map +0 -1
  1032. package/dist/backend/c/stmts.d.ts +0 -76
  1033. package/dist/backend/c/stmts.js +0 -1108
  1034. package/dist/backend/c/stmts.js.map +0 -1
  1035. package/dist/backend/c/types.d.ts +0 -71
  1036. package/dist/backend/c/types.js +0 -459
  1037. package/dist/backend/c/types.js.map +0 -1
  1038. package/dist/backend/c/types.test.js +0 -32
  1039. package/dist/backend/c/types.test.js.map +0 -1
  1040. package/dist/backend/c/walkers.d.ts +0 -134
  1041. package/dist/backend/c/walkers.js +0 -1772
  1042. package/dist/backend/c/walkers.js.map +0 -1
  1043. /package/dist/backend/{c/types.test.d.ts → cycle-analysis.test.d.ts} +0 -0
@@ -1,28 +1,35 @@
1
+ import { objectEnumerationReceiver } from "./object-enumeration-receiver.js";
1
2
  import { InternalCompilerError } from "../../errors.js";
2
3
  /* Call lowering: the lowerCall dispatch chain, parameter-shape analysis and
3
4
  * argument completion (optional/default/rest, explicit-undefined ≡ omission),
4
5
  * function/lambda lowering and signature collection, and monomorphizing
5
6
  * generic instantiation (bounded by MAX_GENERIC_INSTANCES). */
6
7
  import * as ts from "../ts7/adapter.js";
8
+ import { AstNode } from "../ts7/ast-node.js";
7
9
  import { bodyReadsArguments } from "../arguments-usage.js";
8
10
  import { lowerGenMethodCall } from "./lower-generators.js";
9
- import { BIGINT_T, BOOL, CAUGHT, DYN, F64, JSVAL, STRING, SYMBOL_T, UNDEFINED_T, VOID, arrayOf, canBoxFuncIntoDyn, canConvertToDyn, canDynCheckTo, canMarshalTypedFuncIntoIsland, ffiClassType, ffiSourceParamTypes, funcOf, isFfiCallbackParam, isFfiContextParam, isFfiReleaseParam, isUnitType, shapeHasAccessorSlots, typeEquals } from "../../ir/ir.js";
10
- import { isJsSourceFile, isNodeEsmFile, locOf } from "../program.js";
11
- import { genResultRecord, isGenericCallableMemberType, typeKey } from "../type-mapper.js";
12
- import { PoisonError, dynFallbackType, dynUndefinedExpr, importCallHandleType, jsFuncNameOf, newFnCtx, nodeThrowExpr, staticImportNamespaceType } from "./lowerer.js";
13
- import { enforceLibBoundary } from "./lib-boundary.js";
14
- import { NARROW_FIRST, STRING_INDEX_METHODS, STR_METHODS, builtinFenceHintOf, builtinModuleFnOf } from "./surfaces.js";
11
+ import { lowerClassSymbolMethodCall } from "./symbol-methods.js";
12
+ import { errorToStringCall } from "./error-methods.js";
13
+ import { lowerClassPrototypeAssign } from "./class-prototypes.js";
14
+ import { BYTES_ELEMENT_NAME, BIGINT_T, BOOL, CAUGHT, DYN, F64, JSVAL, NULL_T, STRING, SYMBOL_T, UNDEFINED_T, VOID, arrayOf, canBoxFuncIntoDyn, canConvertToDyn, canDynCheckTo, canMarshalTypedFuncIntoIsland, ffiClassType, ffiSourceParamTypes, funcOf, isDynTypedRefType, isFfiCallbackParam, isFfiContextParam, isFfiReleaseParam, isUnitType, shapeHasAccessorSlots, typeEquals } from "../../ir/ir.js";
15
+ import { isJsSourceFile, isNodeEsmFile, locOf, requireSpecOf } from "../program.js";
16
+ import { genResultRecord, isGenericCallableMemberType, jsOpenObjectType, typeKey } from "../type-mapper.js";
17
+ import { PoisonError, dynFallbackType, dynUndefinedExpr, importCallHandleType, jsFuncNameOf, neverTaintedJsType, newFnCtx, nodeThrowExpr, staticImportNamespaceType } from "./lowerer.js";
18
+ import { enforceLibBoundary, lowerSurplusCalls } from "./lib-boundary.js";
19
+ import { NARROW_FIRST, STRING_INDEX_METHODS, STR_METHODS, builtinFenceHintOf, builtinModuleFnOf, stdlibGlobalNameOf } from "./surfaces.js";
15
20
  import { ffiBindingDiag, ffiSignatureDiag, libCallbackDiag, requiresDynamicDiag } from "../../diagnostics/diagnostic.js";
16
21
  import { mixinFnShapeOf } from "./lower-mixins.js";
17
- import { dynStringReceiver, lowerArrayConstructor, lowerArrayFromCall, lowerArrayOfCall, lowerDynArrayFilterCall, lowerDynArrayFlatMapCall, lowerGroupByStaticCall, lowerIteratorHelperCall, lowerObjectAssignIndexShape, lowerObjectFromEntriesCall, lowerObjectIterOverIndexShape, lowerTupleReadMethodCall } from "./lower-containers.js";
18
- import { bufEncoding } from "./containers/bytes.js";
22
+ import { dynStringReceiver, lowerArrayConstructor, lowerArrayFromCall, lowerArrayOfCall, lowerDynArrayFilterCall, lowerDynArrayFlatMapCall, lowerGroupByStaticCall, lowerIteratorHelperCall, lowerObjectAssignIndexShape, lowerObjectConstructor, lowerObjectFromEntriesCall, lowerObjectIterOverIndexShape, lowerTupleReadMethodCall } from "./lower-containers.js";
23
+ import { lowerBytesStaticCall } from "./containers/bytes.js";
19
24
  import { lowerRegexMethodCall, lowerStringIndexCall, lowerStringMethodCall, lowerStringPaddingCall, lowerStringSplitCall } from "./containers/string-and-regexp.js";
20
- import { lowerChildStreamMethodCall, lowerChildWriterMethodCall, lowerCreateRequireCall, lowerCryptoHashMethodCall, lowerDirentMethodCall, lowerFileHandleMethodCall, lowerImportMetaResolveCall, lowerNodeModuleCall, lowerPerfHooksCall, lowerProcStreamMethodCall, lowerReflectApplyCall, lowerRequireResolveCall, lowerWatcherMethodCall } from "./lower-builtins.js";
21
- import { lowerAbsenceProbe, lowerPromiseAllTupleCall, lowerPromiseRejectCall, stringWrapperToString, templateRawTextOf } from "./lower-exprs.js";
25
+ import { createRequireSpecOf, lowerChildStreamMethodCall, lowerChildWriterMethodCall, lowerCreateRequireCall, lowerCryptoHashMethodCall, lowerDirentMethodCall, lowerFileHandleMethodCall, lowerImportMetaResolveCall, lowerNodeModuleCall, lowerPerfHooksCall, lowerProcStreamMethodCall, lowerReflectCall, lowerRequireResolveCall, lowerWatcherMethodCall } from "./lower-builtins.js";
26
+ import { lowerAbsenceProbe, lowerPromiseAllTupleCall, lowerPromiseRejectCall, stringWrapperToString, symbolFieldInfo, templateRawTextOf } from "./lower-exprs.js";
22
27
  import { isSafeToDiscard } from "./expressions/evaluation-safety.js";
23
28
  import { tryLowerExpression } from "./expressions/try-lower-expression.js";
29
+ import { hasRuntimeStatics } from "./class-runtime-statics.js";
24
30
  import { httpClientFnBindingOf, isStreamUndefCallExpr, lowerCompatReqStreamOptionalCall, lowerHttpClientFnCall } from "./lower-server.js";
25
- import { EMITTER_API_MEMBERS, exactInstanceClassOf, findGenericMethodOn, lowerClassGenericMethodCall, lowerStaticMethodCall } from "./lower-classes.js";
31
+ import { EMITTER_API_MEMBERS, exactClassOfReceiver, exactInstanceClassOf, findGenericMethodOn, lowerClassGenericMethodCall, lowerStaticMethodCall, lowerStaticFieldRead, returnsOnlyThis, storedClassValueType } from "./lower-classes.js";
32
+ import { classCallbackCall, isClassCallback } from "./class-callbacks.js";
26
33
  import { emitterRooted, lowerEmitterMethodCall } from "./lower-event-emitter.js";
27
34
  import { lowerConsoleInspectArg, lowerFormatCall } from "./lower-inspect.js";
28
35
  import { STREAM_API_MEMBERS, lowerStreamMethodCall, lowerStreamModuleCall, lowerStreamStaticCall, streamSidesOf } from "./lower-stream.js";
@@ -30,10 +37,14 @@ import { ambientNsRootOf, ambientUndefReadType, ambientUndefVarRootOf, ambientUn
30
37
  import { declSymbolOf } from "./lower-modules.js";
31
38
  import { expandoMemberRead } from "./lower-expando.js";
32
39
  import { npmStaticPackageOfPath } from "../npm-static.js";
33
- import { countedFor, varRef } from "../../ir/build.js";
40
+ import { countedFor, numLit, varRef } from "../../ir/build.js";
34
41
  import { rejectStaticThis } from "./static-this.js";
35
42
  import { fenceNodeModuleMutationCall, lowerRequireCacheKeys } from "./lower-node-module.js";
36
43
  import { defaultAfterUndefined, lowerOptionalArgument, lowerStaticallyUndefinedArgument, positionNumber } from "./optional-arguments.js";
44
+ import { fenceSymbolFieldCopy } from "./symbol-fields.js";
45
+ import { lowerClassDataDescriptor, lowerClassDescriptorRead } from "./class-descriptors.js";
46
+ import { classStaticDataFor } from "./class-static-data.js";
47
+ import { jsBindingHasOpenWrites } from "./lower-stmts.js";
37
48
  export { bodyReadsArguments };
38
49
  /** The one func-type projection of completed parameter shapes. Typed rest
39
50
  * parameters keep their packed array as the trailing native ABI slot and
@@ -51,11 +62,7 @@ export function funcTypeFromParamShapes(shapes, ret) {
51
62
  ret,
52
63
  ...(typedRest || dynRest || islandRest || argumentsAll ? { rest: true } : {}),
53
64
  ...(argumentsAll ? { argumentsAll: true } : {}),
54
- ...(typedRest
55
- ? { restAbi: "typed" }
56
- : islandRest
57
- ? { restAbi: "jsval" }
58
- : {}),
65
+ ...(typedRest || islandRest ? { restAbi: typedRest ? "typed" : "jsval" } : {}),
59
66
  };
60
67
  }
61
68
  /** Registers `const alias = overloadedDeclaration` as a compile-time
@@ -118,6 +125,25 @@ export const MAX_GENERIC_INSTANCES = 100;
118
125
  * - `...xs: T[]`: the ABI type is the array; call sites pack the surplus.
119
126
  */
120
127
  export function paramShape(lowerer, param) {
128
+ if (param.initializer && isJsSourceFile(param.getSourceFile()) && !param.type &&
129
+ !/@(?:param|type)\b/.test(param.getSourceFile().text.slice(param.parent?.pos ?? param.pos, param.getStart()))) {
130
+ return { type: DYN, mode: "omittable", bodyType: DYN };
131
+ }
132
+ // Inferred JS array patterns describe the bindings, not an exact tuple
133
+ // contract. Consume the actual iterable, including surplus elements.
134
+ if (ts.isArrayBindingPattern(param.name) && isJsSourceFile(param.getSourceFile()) && !param.type &&
135
+ !/@(?:param|type)\b/.test(param.getSourceFile().text.slice(param.parent?.pos ?? param.pos, param.getStart()))) {
136
+ if (param.dotDotDotToken)
137
+ return { type: DYN, mode: "dynRest" };
138
+ return param.initializer ? { type: DYN, mode: "omittable", bodyType: DYN } : { type: DYN, mode: "required" };
139
+ }
140
+ if (lowerer.checkedCallbackParams.has(param)) {
141
+ if (param.dotDotDotToken)
142
+ return { type: DYN, mode: "dynRest" };
143
+ return param.initializer
144
+ ? { type: DYN, mode: "omittable", bodyType: DYN }
145
+ : { type: DYN, mode: "required" };
146
+ }
121
147
  const moduleNs = lowerer.moduleNsParamOverrides.get(param);
122
148
  if (moduleNs !== undefined) {
123
149
  return { type: moduleNs, mode: param.questionToken ? "omittable" : "required" };
@@ -159,21 +185,7 @@ export function paramShape(lowerer, param) {
159
185
  // default when the argument was omitted or undefined, then the
160
186
  // pattern destructures the picked value (declareParams).
161
187
  const raw = lowerer.irTypeOf(param.name);
162
- // A DYNAMIC-TIER pattern source (`function f({} = a)` with
163
- // `a: any` — jsval for island values, dyn for the checked-dynamic
164
- // dyn): the slot holds its tier's undefined DIRECTLY, so the ABI
165
- // is the slot itself — no synthesized union; the prologue tests
166
- // undefined at runtime (declareParams).
167
- if (raw.kind === "dyn" || raw.kind === "jsval") {
168
- return { type: raw, mode: "omittable", bodyType: raw };
169
- }
170
- const bodyType = lowerer.stripUndefinedArm(raw);
171
- lowerer.checkDefaultParamBodyType(param, bodyType);
172
- const abi = bodyType.kind === "union" ? lowerer.withUndefinedArmOf(bodyType) : lowerer.withUndefinedArm(bodyType);
173
- if (!abi) {
174
- lowerer.badType(param.name, lowerer.typeOf(param.name)); // defensive: unknown union id
175
- }
176
- return { type: abi, mode: "omittable", bodyType };
188
+ return defaultParameterShape(lowerer, param, raw);
177
189
  }
178
190
  return { type: lowerer.runtimeOptionalBindingType(param.name, lowerer.irTypeOf(param.name)), mode: "required" };
179
191
  }
@@ -207,41 +219,12 @@ export function paramShape(lowerer, param) {
207
219
  }
208
220
  if (param.initializer) {
209
221
  const raw = lowerer.irTypeOf(param.name);
210
- // A DYNAMIC-TIER defaulted param (`function f(x = a)` with `a: any`
211
- // — tsc types x any; jsval for island values, dyn for the checked-
212
- // dynamic dyn): the slot holds its tier's undefined directly, so
213
- // the ABI is the slot itself and the prologue's default test is the
214
- // runtime undefined test (declareParams).
215
- if (raw.kind === "dyn" || raw.kind === "jsval") {
216
- return { type: raw, mode: "omittable", bodyType: raw };
217
- }
218
- // A default that may ITSELF be undefined (`x = process.env.FOO`):
219
- // tsc keeps undefined in the body's type, so there is nothing to
220
- // narrow — the ABI union IS the body type and the prologue passes a
221
- // present argument through unchanged (declareParams's pass-through
222
- // branch). The generic strip-and-narrow below would demand a
223
- // `string`-typed default and fence on the union re-tag.
224
- if (lowerer.bareUndefinedArmedUnion(raw)) {
225
- const initT = lowerer.mapTypeOf(lowerer.typeOf(param.initializer));
226
- if (initT && (initT.kind === "undefinedT" || lowerer.bareUndefinedArmedUnion(initT))) {
227
- return { type: raw, mode: "omittable", bodyType: raw };
228
- }
229
- }
230
- const bodyType = lowerer.stripUndefinedArm(raw);
231
- lowerer.checkDefaultParamBodyType(param, bodyType);
232
- // A UNION body type (`tlds: string | string[] = "localhost"`) arms
233
- // the ABI with undefined ON TOP of the body's arms; the prologue
234
- // re-tags a present argument back into the body union (undefined
235
- // sorts last among arm typeKeys in practice, so the mapping is
236
- // usually the identity prefix — the interned retag helper handles
237
- // any order).
238
- const abi = bodyType.kind === "union" ? lowerer.withUndefinedArmOf(bodyType) : lowerer.withUndefinedArm(bodyType);
239
- if (!abi) {
240
- lowerer.badType(param.name, lowerer.typeOf(param.name)); // defensive: unknown union id
241
- }
242
- return { type: abi, mode: "omittable", bodyType };
222
+ return defaultParameterShape(lowerer, param, raw);
243
223
  }
244
224
  const type = lowerer.runtimeOptionalBindingType(param.name, lowerer.irTypeOf(param.name));
225
+ if (type.kind === "void") {
226
+ return { type: DYN, mode: param.questionToken ? "omittable" : "required" };
227
+ }
245
228
  if (param.questionToken && !lowerer.bareUndefinedArmedUnion(type) && type.kind !== "dyn" && type.kind !== "jsval") {
246
229
  // `x?: unknown` where unknown came from an annotation: undefined is
247
230
  // absorbed into the hole type, so no undefined ARM exists — but a
@@ -269,7 +252,7 @@ export function paramShapes(lowerer, params, signature, blameOf) {
269
252
  return params.map((declParam, i) => {
270
253
  const symbol = signature.getParameters()[i];
271
254
  const tsType = symbol ? lowerer.checker.getTypeOfSymbol(symbol) : lowerer.typeOf(declParam.name);
272
- const mapped = lowerer.runtimeOptionalBindingType(declParam.name, lowerer.mapTypeOf(tsType) ?? lowerer.irTypeOf(declParam.name));
255
+ const mapped = jsOpenObjectType(declParam, lowerer.runtimeOptionalBindingType(declParam.name, lowerer.mapTypeOf(tsType) ?? lowerer.irTypeOf(declParam.name)), lowerer.shapes, lowerer.unions);
273
256
  if (!mapped || mapped.kind === "void")
274
257
  lowerer.badType(blameOf?.(declParam, i) ?? declParam.name, tsType);
275
258
  if (declParam.dotDotDotToken) {
@@ -277,30 +260,46 @@ export function paramShapes(lowerer, params, signature, blameOf) {
277
260
  lowerer.badType(blameOf?.(declParam, i) ?? declParam.name, tsType);
278
261
  return { type: mapped, mode: "rest" };
279
262
  }
280
- if (declParam.initializer) {
281
- if (mapped.kind === "dyn" || mapped.kind === "jsval") {
282
- return { type: mapped, mode: "omittable", bodyType: mapped };
283
- }
284
- const bodyType = lowerer.stripUndefinedArm(mapped);
285
- lowerer.checkDefaultParamBodyType(declParam, bodyType);
286
- return { type: lowerer.withUndefinedArm(bodyType), mode: "omittable", bodyType };
287
- }
263
+ if (declParam.initializer)
264
+ return defaultParameterShape(lowerer, declParam, mapped);
288
265
  if (declParam.questionToken && !lowerer.bareUndefinedArmedUnion(mapped)) {
289
266
  lowerer.unsupported("SC1090", declParam, `optional parameters of type '${lowerer.fmt(mapped)}'`);
290
267
  }
291
268
  return { type: mapped, mode: declParam.questionToken ? "omittable" : "required" };
292
269
  });
293
270
  }
271
+ /** A default expression may itself yield undefined. Keep that arm in the
272
+ * body and parameter-property storage, including for literal `undefined`
273
+ * and void expressions: the general type mapper represents those as VOID,
274
+ * so checking only a mapped undefinedT silently erased a valid value.
275
+ * Shared by declared and instantiated signatures, including destructuring. */
276
+ function defaultParameterShape(lowerer, param, raw) {
277
+ if (raw.kind === "dyn" || raw.kind === "jsval") {
278
+ return { type: raw, mode: "omittable", bodyType: raw };
279
+ }
280
+ if (lowerer.bareUndefinedArmedUnion(raw) && param.initializer) {
281
+ const initializer = lowerer.typeOf(param.initializer);
282
+ const parts = initializer.isUnionType() ? ts.constituentTypes(initializer) : [initializer];
283
+ if (parts.some((part) => (part.flags & (ts.TypeFlags.Undefined | ts.TypeFlags.Void)) !== 0)) {
284
+ return { type: raw, mode: "omittable", bodyType: raw };
285
+ }
286
+ }
287
+ const bodyType = lowerer.stripUndefinedArm(raw);
288
+ lowerer.checkDefaultParamBodyType(param, bodyType);
289
+ const abi = bodyType.kind === "union" ? lowerer.withUndefinedArmOf(bodyType) : lowerer.withUndefinedArm(bodyType);
290
+ if (!abi)
291
+ lowerer.badType(param.name, lowerer.typeOf(param.name));
292
+ return { type: abi, mode: "omittable", bodyType };
293
+ }
294
294
  /** The fences on a defaulted parameter's body type: it becomes the value
295
295
  * arm of the synthesized `T | undefined` ABI union, so it must be a valid
296
- * single arm. func and Set ARE valid here: the ABI union's only test is
296
+ * single arm. Functions, Maps and Sets are valid: the ABI union's test is
297
297
  * the prologue's own undefined-tag check (never a user narrowing, which
298
- * is what keeps map/set out of general unions), so `runner: Runner =
298
+ * is what keeps containers out of unions with data siblings), so `runner: Runner =
299
299
  * defaultRunner` and `skip: Set<string> = new Set()` arm like any ref
300
300
  * kind — the nullable-callback union shape, built by the compiler. */
301
301
  export function checkDefaultParamBodyType(lowerer, param, bodyType) {
302
302
  if (bodyType.kind === "void" ||
303
- bodyType.kind === "map" ||
304
303
  bodyType.kind === "regex" ||
305
304
  bodyType.kind === "date" ||
306
305
  bodyType.kind === "dyn" ||
@@ -336,7 +335,62 @@ export function completeArgs(lowerer, argNodes, shapes, loc, blame,
336
335
  * coercion an ordinary argument gets (coerceInto against its shape,
337
336
  * DYN conversion in a dyn rest, element coercion in a typed rest). */
338
337
  leading) {
339
- const isIr = (s) => s !== undefined && !("kind" in s);
338
+ // Conversion eligibility can traverse the whole recursive parameter
339
+ // graph. Ordinary calls and fixed tuples never need that analysis.
340
+ if (argNodes.some((arg) => ts.isSpreadElement(arg) && !fixedTupleSpreadInfo(lowerer, arg.expression)) &&
341
+ canCompleteRuntimeSpread(lowerer, shapes)) {
342
+ // Runtime-length spreads determine the complete argument list before
343
+ // any parameter default runs. Build it once in source order, then
344
+ // extract the fixed native ABI slots; missing elements are undefined.
345
+ const pack = lowerer.declareHiddenLocal("%spreadArgs", DYN);
346
+ const ref = () => ({ kind: "varRef", localId: pack.id, type: DYN, loc });
347
+ const stmts = [{ kind: "varDecl", localId: pack.id, init: { kind: "dynArrLit", elems: [], type: DYN, loc }, loc }];
348
+ const push = (value, fn) => {
349
+ stmts.push({ kind: "exprStmt", expr: { kind: "libCall", fn, args: [ref(), value], type: VOID, loc: value.loc }, loc: value.loc });
350
+ };
351
+ for (const value of leading ?? [])
352
+ push(lowerer.coerceInto(blame, value, DYN), "dyn.packPush");
353
+ const spreads = argNodes.filter(ts.isSpreadElement).length;
354
+ argNodes.forEach((arg, index) => {
355
+ if (!ts.isSpreadElement(arg)) {
356
+ push(lowerer.lowerExprExpecting(arg, DYN), "dyn.packPush");
357
+ return;
358
+ }
359
+ let value = lowerer.lowerExpr(arg.expression);
360
+ if (value.type.kind === "set") {
361
+ value = { kind: "setIntrinsic", method: "toArray", receiver: value, args: [], type: arrayOf(value.type.elem), loc: value.loc };
362
+ }
363
+ else if (value.type.kind === "object") {
364
+ value = lowerer.classIteratorDrainCall(value, locOf(arg)) ?? value;
365
+ }
366
+ if (value.type.kind === "array") {
367
+ // Argument iteration materializes holes as present undefined
368
+ // before conversion to the dense checked-dynamic argument pack.
369
+ value = { kind: "arrayLit", elems: [value], spreads: [0], type: value.type, loc: value.loc };
370
+ }
371
+ value = lowerer.coerceInto(arg.expression, value, DYN);
372
+ if (spreads === 1 && index === argNodes.length - 1) {
373
+ stmts.push({ kind: "exprStmt", expr: {
374
+ kind: "libCall", fn: "dyn.packPushSpread", args: [ref(), value, { kind: "strLit", value: arg.expression.getText(), type: STRING, loc }], type: VOID, loc,
375
+ }, loc });
376
+ }
377
+ else
378
+ push(value, "dyn.packPushSpreadIter");
379
+ });
380
+ const args = shapes.map((shape, index) => {
381
+ if (shape.mode === "arguments")
382
+ return ref();
383
+ const value = shape.mode === "rest" || shape.mode === "dynRest"
384
+ ? { kind: "dynInvoke", recv: ref(), method: "slice", calleeName: "arguments.slice", args: [{ kind: "dynFrom", value: { kind: "numLit", value: index, type: F64, loc }, type: DYN, loc }], type: DYN, loc }
385
+ : { kind: "dynKeyGet", value: ref(), key: { kind: "strLit", value: String(index), type: STRING, loc }, type: DYN, loc };
386
+ return lowerer.coerceInto(blame, value, shape.type);
387
+ });
388
+ // Every supported form has at least one native slot to carry the
389
+ // evaluation prefix, including calls whose only slot is their rest.
390
+ args[0] = { kind: "seqExpr", stmts, result: args[0], type: args[0].type, loc };
391
+ return args;
392
+ }
393
+ const isIr = (s) => s !== undefined && !(s instanceof AstNode);
340
394
  const sources = leading?.map((ir) => ({ ir })) ?? [];
341
395
  for (const arg of argNodes) {
342
396
  if (!ts.isSpreadElement(arg)) {
@@ -399,9 +453,20 @@ leading) {
399
453
  lowerer.unsupported("SC1090", source, "spread arguments into fixed parameter positions (a spread can only fill a rest parameter)");
400
454
  }
401
455
  const slotType = i < restAt ? positional[i].type : DYN;
402
- const value = isIr(source)
403
- ? lowerer.coerceInto(blame, source.ir, slotType)
404
- : lowerer.lowerExprExpecting(source, slotType);
456
+ let value;
457
+ if (isIr(source)) {
458
+ let ir = source.ir;
459
+ // Tuple-spread storage also feeds later arguments. Declare it in
460
+ // this shared sequence, not inside one argument's initializer,
461
+ // whose statement frame ends before the next field is read.
462
+ if (ir.kind === "seqExpr") {
463
+ stmts.push(...ir.stmts);
464
+ ir = ir.result;
465
+ }
466
+ value = lowerer.coerceInto(blame, ir, slotType);
467
+ }
468
+ else
469
+ value = lowerer.lowerExprExpecting(source, slotType);
405
470
  const saved = lowerer.declareHiddenLocal("%callArg", slotType);
406
471
  stmts.push({ kind: "varDecl", localId: saved.id, init: value, loc: value.loc });
407
472
  return { kind: "varRef", localId: saved.id, type: slotType, loc: value.loc };
@@ -409,7 +474,7 @@ leading) {
409
474
  const fixed = positional.map((shape, i) => {
410
475
  if (i < passed.length)
411
476
  return passed[i];
412
- if (shape.mode === "omittable")
477
+ if (shape.mode === "omittable" || lowerer.bareUndefinedArmedUnion(shape.type))
413
478
  return shape.callDefault ?? lowerer.undefinedArgFor(shape.type, loc, blame);
414
479
  if (shape.type.kind === "dyn")
415
480
  return { kind: "dynFrom", value: { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc }, type: DYN, loc };
@@ -434,9 +499,19 @@ leading) {
434
499
  // completion has no home for that. Spreads fill REST slots only.
435
500
  lowerer.unsupported("SC1090", arg, "spread arguments into fixed parameter positions (a spread can only fill a rest parameter)");
436
501
  }
437
- if (arg)
502
+ if (arg) {
503
+ let operand = arg;
504
+ while (ts.isParenthesizedExpression(operand))
505
+ operand = operand.expression;
506
+ if (ts.isVoidExpression(operand)) {
507
+ const absent = omittedArgFor(lowerer, shape.type, loc);
508
+ const effect = lowerStaticallyUndefinedArgument(lowerer, operand);
509
+ if (absent && effect)
510
+ return defaultAfterUndefined(effect, absent);
511
+ }
438
512
  return lowerer.lowerExprExpecting(arg, shape.type);
439
- if (shape.mode !== "omittable") {
513
+ }
514
+ if (shape.mode !== "omittable" && !lowerer.bareUndefinedArmedUnion(shape.type)) {
440
515
  // A missing argument for a CHECKED-DYNAMIC param (an implicit-any
441
516
  // JS signature called short — `mustCall(fn)` with `expected`
442
517
  // omitted): JS fills undefined, and the dyn slot holds exactly
@@ -565,8 +640,7 @@ leading) {
565
640
  lowerer.unsupported("SC1090", a, "spread arguments into fixed parameter positions (a spread can only fill a rest parameter)");
566
641
  }
567
642
  const v = lowerer.lowerExpr(a);
568
- if (v.kind !== "unitLit" && v.kind !== "numLit" && v.kind !== "strLit" &&
569
- v.kind !== "boolLit" && v.kind !== "varRef" && v.kind !== "closure") {
643
+ if (!isSafeToDiscard(v)) {
570
644
  lowerer.unsupported("SC1090", a, "surplus arguments with side effects (JS evaluates surplus arguments to a function without a rest parameter, then drops them; only effect-free surplus arguments compile)");
571
645
  }
572
646
  }
@@ -690,7 +764,9 @@ export function requireExactArityValue(lowerer, blame, contextual, shapes, funcT
690
764
  // slot): judge by the expression's OWN completed type; the slot's
691
765
  // coercion still enforces (or adapts) the flow it lands in.
692
766
  if (mappedFn?.kind !== "func" && contextual) {
693
- mappedFn = lowerer.mapTypeOf(lowerer.typeOf(contextual));
767
+ const ownType = lowerer.typeOf(contextual);
768
+ mappedFn = lowerer.mapTypeOf(ownType) ??
769
+ (isJsSourceFile(contextual.getSourceFile()) ? dynFallbackType(lowerer, contextual, ownType) : null);
694
770
  }
695
771
  if (mappedFn && typeEquals(mappedFn, funcType))
696
772
  return;
@@ -795,7 +871,7 @@ export function appendImplicitUndefinedReturn(lowerer, body, bodyReturn, loc) {
795
871
  /** A declaration's checker-derived IR return type. The unmappable-type
796
872
  * diagnostic points at `blame` (the name for top-level declarations, the
797
873
  * whole node for lambda-likes — preserving each caller's historical loc). */
798
- function hasExplicitJsDocReturn(decl) {
874
+ export function hasExplicitJsDocReturn(decl) {
799
875
  const sourceFile = decl.getSourceFile();
800
876
  return /@returns?\b/.test(sourceFile.text.slice(decl.pos, decl.getStart(sourceFile)));
801
877
  }
@@ -805,11 +881,25 @@ function promiseCarriesDyn(lowerer, type) {
805
881
  return type.kind === "union" &&
806
882
  (lowerer.unions.get(type.unionId)?.arms.some((arm) => promiseCarriesDyn(lowerer, arm)) ?? false);
807
883
  }
884
+ function producesConstructor(lowerer, type) {
885
+ let result = type;
886
+ for (let depth = 0; result && depth < 8; depth++) {
887
+ if (lowerer.checker.getConstructSignatures(result).length > 0)
888
+ return true;
889
+ const signatures = lowerer.checker.getCallSignatures(result);
890
+ result = signatures.length === 1 ? lowerer.checker.getReturnTypeOfSignature(signatures[0]) : undefined;
891
+ }
892
+ return false;
893
+ }
808
894
  export function declaredReturnType(lowerer, decl, blame) {
809
895
  const sig = lowerer.checker.getSignatureFromDeclaration(decl);
810
896
  if (!sig)
811
897
  lowerer.unsupported("SC1090", decl, "this function form");
812
898
  const retTsType = lowerer.checker.getReturnTypeOfSignature(sig);
899
+ // An inferred null/undefined return in JS can read a mutable checked-value
900
+ // field. Keep the actual value instead of restricting it to the initializer.
901
+ if (isJsSourceFile(decl.getSourceFile()) && (retTsType.flags & (ts.TypeFlags.Null | ts.TypeFlags.Undefined)) !== 0)
902
+ return DYN;
813
903
  // A body that always throws infers `never` — as a RETURN type that is
814
904
  // void with a stronger guarantee (`() => never` is assignable to
815
905
  // `() => void`), and throw-only callbacks are ordinary code
@@ -817,10 +907,36 @@ export function declaredReturnType(lowerer, decl, blame) {
817
907
  if (retTsType.flags & ts.TypeFlags.Never)
818
908
  return VOID;
819
909
  const mappedReturn = lowerer.mapTypeOf(retTsType);
910
+ if (isJsSourceFile(decl.getSourceFile()) && mappedReturn?.kind === "array" && mappedReturn.elem.kind === "f64")
911
+ return DYN;
912
+ if (isJsSourceFile(decl.getSourceFile()) && !decl.type && !hasExplicitJsDocReturn(decl) && mappedReturn?.kind === "date")
913
+ return DYN;
914
+ // JS inference assigns Number to arithmetic over any, although the
915
+ // runtime operands can both be BigInts. Preserve that native result.
916
+ if (isJsSourceFile(decl.getSourceFile()) && !decl.type && !hasExplicitJsDocReturn(decl) &&
917
+ mappedReturn?.kind === "f64") {
918
+ let numericAnyReturn = false;
919
+ const numeric = new Set([ts.SyntaxKind.MinusToken, ts.SyntaxKind.AsteriskToken,
920
+ ts.SyntaxKind.SlashToken, ts.SyntaxKind.PercentToken, ts.SyntaxKind.AsteriskAsteriskToken]);
921
+ const check = (node) => {
922
+ if (node !== decl && ts.isFunctionLike(node))
923
+ return;
924
+ const value = ts.isReturnStatement(node) ? node.expression
925
+ : node === decl && ts.isArrowFunction(decl) && !ts.isBlock(decl.body) ? decl.body : undefined;
926
+ if (value && ts.isBinaryExpression(value) && numeric.has(value.operatorToken.kind) &&
927
+ [value.left, value.right].some((operand) => (lowerer.typeOf(operand).flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) !== 0))
928
+ numericAnyReturn = true;
929
+ node.forEachChild(check);
930
+ };
931
+ check(decl);
932
+ if (numericAnyReturn)
933
+ return DYN;
934
+ }
820
935
  if (isJsSourceFile(decl.getSourceFile()) &&
821
936
  !hasExplicitJsDocReturn(decl) &&
822
937
  mappedReturn !== null &&
823
938
  promiseCarriesDyn(lowerer, mappedReturn) &&
939
+ !decl.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword) &&
824
940
  decl.parameters.some((param) => {
825
941
  const mapped = lowerer.mapTypeOf(lowerer.typeOf(param.name));
826
942
  return mapped === null || mapped.kind === "dyn";
@@ -852,14 +968,22 @@ export function declaredReturnType(lowerer, decl, blame) {
852
968
  // checked-dynamic (or none): a lambda with RECORD-typed parameters
853
969
  // (a reduce reducer over a typed array) legitimately returns its
854
970
  // parameters' records and keeps the static type.
971
+ // Native-only members (such as Int32Array layout offsets) cannot cross
972
+ // that boundary; their factories keep the native record ABI.
973
+ const asyncReturn = decl.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword) && mappedReturn?.kind === "promise";
974
+ const recordReturn = asyncReturn ? mappedReturn.inner : mappedReturn;
975
+ const recordArms = recordReturn?.kind === "union" ? lowerer.unions.get(recordReturn.unionId)?.arms : recordReturn ? [recordReturn] : undefined;
976
+ const inferredRecordReturn = recordArms?.some((arm) => arm.kind === "record" || arm.kind === "object") &&
977
+ recordArms.every((arm) => isUnitType(arm) || arm.kind === "record" || arm.kind === "object" && !hasExplicitJsDocReturn(decl));
855
978
  if (isJsSourceFile(decl.getSourceFile()) &&
856
979
  decl.type === undefined &&
857
- lowerer.mapTypeOf(retTsType)?.kind === "record" &&
980
+ recordReturn !== null && recordReturn !== undefined && inferredRecordReturn &&
981
+ lowerer.dynConvertible(recordReturn) &&
858
982
  decl.parameters.every((p) => {
859
983
  const mt = lowerer.mapTypeOf(lowerer.typeOf(p));
860
984
  return mt === null || mt.kind === "dyn";
861
985
  })) {
862
- return DYN;
986
+ return asyncReturn ? { kind: "promise", inner: DYN } : DYN;
863
987
  }
864
988
  const returnType = lowerer.mapTypeOf(retTsType);
865
989
  if (!returnType) {
@@ -884,7 +1008,7 @@ export function declaredReturnType(lowerer, decl, blame) {
884
1008
  * other unmappable type (the caller's badType reports those). */
885
1009
  function fenceGenericSignatureResult(lowerer, blame, t) {
886
1010
  const parts = t.isUnionType() ? ts.constituentTypes(t) : [t];
887
- if (!parts.some((p) => lowerer.checker.getCallSignatures(p).some((s) => (s.typeParameters?.length ?? 0) > 0))) {
1011
+ if (!parts.some((p) => lowerer.checker.getCallSignatures(p).some((s) => s.getTypeParameters().length > 0))) {
888
1012
  return;
889
1013
  }
890
1014
  lowerer.unsupported("SC1090", blame, `results that are themselves generic functions ('${lowerer.checker.typeToString(t)}' keeps its type parameters — no call-site instantiation pins them, and the returned value would need the producing call's frame; restructure to one generic function taking all arguments)`);
@@ -961,7 +1085,7 @@ export function collectSignatureInner(lowerer, decl) {
961
1085
  if (!params.some((sh) => sh.mode === "rest" || sh.mode === "dynRest" || sh.mode === "islandRest") &&
962
1086
  isJsSourceFile(decl.getSourceFile()) &&
963
1087
  bodyReadsArguments(decl)) {
964
- if (decl.parameters.length > 0 && !isNodeEsmFile(decl.getSourceFile())) {
1088
+ if (decl.parameters.length > 0 && !isNodeEsmFile(decl.getSourceFile(), lowerer.program)) {
965
1089
  lowerer.unsupported("SC1090", decl, "parameterized 'arguments' outside an ES module (sloppy-mode parameter aliases)");
966
1090
  }
967
1091
  params.push({ type: DYN, mode: decl.parameters.length > 0 ? "arguments" : "dynRest" });
@@ -1193,7 +1317,7 @@ export function inferTypeParamBindings(lowerer, expr, info, rsig, tsBindings) {
1193
1317
  return;
1194
1318
  const taT = lowerer.checker.getTypeFromTypeNode(ta);
1195
1319
  const mapped = lowerer.mapTypeOf(taT);
1196
- if (mapped && mapped.kind !== "void") {
1320
+ if (mapped) {
1197
1321
  bindings.set(tp, mapped);
1198
1322
  tsBindings?.set(tp, taT);
1199
1323
  }
@@ -1213,7 +1337,7 @@ function bindDefaultTypeParams(lowerer, typeParams, typeParamDecls, bindings, ts
1213
1337
  return;
1214
1338
  const defT = lowerer.checker.getTypeFromTypeNode(tpDecl.defaultType);
1215
1339
  const mapped = lowerer.mapTypeOf(defT);
1216
- if (mapped && mapped.kind !== "void") {
1340
+ if (mapped) {
1217
1341
  bindings.set(tp, mapped);
1218
1342
  tsBindings?.set(tp, defT);
1219
1343
  }
@@ -1255,7 +1379,10 @@ function unifySignatureBindings(lowerer, info, rsig, bindings, tsBindings) {
1255
1379
  }
1256
1380
  if (!bindings.has(sym)) {
1257
1381
  const mapped = lowerer.mapTypeOf(inst);
1258
- if (mapped && mapped.kind !== "void")
1382
+ // A visitor's inferred T can be void. It still binds the
1383
+ // return convention of `(node) => T`; discarding it leaves
1384
+ // the callback's return type spuriously uninstantiated.
1385
+ if (mapped)
1259
1386
  bindings.set(sym, mapped);
1260
1387
  }
1261
1388
  }
@@ -1270,10 +1397,20 @@ function unifySignatureBindings(lowerer, info, rsig, bindings, tsBindings) {
1270
1397
  // unbound type parameter surfaces as a mapping diagnostic later).
1271
1398
  if (declared.isUnionType()) {
1272
1399
  const unitFlags = ts.TypeFlags.Undefined | ts.TypeFlags.Null;
1273
- const dParts = ts.constituentTypes(declared).filter((t) => !(t.flags & unitFlags));
1274
- const iParts = inst.isUnionType() ? ts.constituentTypes(inst).filter((t) => !(t.flags & unitFlags)) : [inst];
1400
+ const declaredParts = ts.constituentTypes(declared);
1401
+ const declaredUnits = declaredParts.reduce((flags, t) => flags | (t.flags & unitFlags), 0);
1402
+ const dParts = declaredParts.filter((t) => !(t.flags & unitFlags));
1403
+ const iParts = inst.isUnionType() ? ts.constituentTypes(inst).filter((t) => !(t.flags & declaredUnits)) : [inst];
1275
1404
  if (dParts.length === 1 && iParts.length === 1)
1276
1405
  unify(dParts[0], iParts[0], depth + 1);
1406
+ else if (dParts.length === 1 && iParts.length > 1 &&
1407
+ iParts.every((t) => (t.flags & unitFlags) === 0)) {
1408
+ // T | undefined can receive boolean | undefined: boolean itself
1409
+ // has two literal arms. There is still one declared data slot,
1410
+ // so match it against the whole remaining union. Removing null
1411
+ // too is safe only when no undeclared null arm remains.
1412
+ unify(dParts[0], lowerer.checker.getNonNullableType(inst), depth + 1);
1413
+ }
1277
1414
  return;
1278
1415
  }
1279
1416
  // Instantiations of the SAME generic ALIAS (Partial<T> vs
@@ -1426,16 +1563,21 @@ export function lowerGenericInstance(lowerer, info, inst) {
1426
1563
  fnCtx.generator = generatorMeta(lowerer, inst.returnType);
1427
1564
  }
1428
1565
  lowerer.fnStack.push(fnCtx);
1566
+ lowerer.localClassInstantiations.push({ owner: decl, name: inst.name });
1429
1567
  try {
1430
- // STATIC generic methods: `this`/`super` name the RECEIVER class (a
1431
- // dynamic value) — the lowerStaticMethod fence, applied here because
1432
- // generic statics have no non-generic lowering pass. Arrow functions
1433
- // are transparent (they inherit the method's `this`); this-binding
1434
- // function forms are opaque.
1568
+ // Static specializations bind lexical this only when the caller
1569
+ // proved its exact receiver. Other instances retain the fence;
1570
+ // super remains unsupported. Arrows inherit the lexical receiver.
1435
1571
  if (info.member?.kind === "static" && decl.body) {
1436
- rejectStaticThis(lowerer, decl.body, (keyword) => `'${keyword}' in static methods (it names the RECEIVER class — a dynamic value; reference the class by name instead)`);
1572
+ rejectStaticThis(lowerer, decl.body, (keyword) => `'${keyword}' in static methods (it names the RECEIVER class — a dynamic value; reference the class by name instead)`, false, info.staticReceiver !== undefined);
1437
1573
  }
1438
1574
  const params = [];
1575
+ const receiverInit = [];
1576
+ if (info.staticReceiver) {
1577
+ const value = lowerer.classValueRef(info.staticReceiver, decl);
1578
+ const local = lowerer.declareThis(value.type);
1579
+ receiverInit.push({ kind: "varDecl", localId: local.id, init: value, loc: locOf(decl) });
1580
+ }
1439
1581
  if (cls && info.member.kind === "method") {
1440
1582
  // Instance methods take `this` as param 0, exactly like plain
1441
1583
  // `%C.method` functions (lowerClassMethodMemberInner).
@@ -1447,12 +1589,13 @@ export function lowerGenericInstance(lowerer, info, inst) {
1447
1589
  // threaded — a default mentioning T resolves like any body expression.
1448
1590
  const declared = lowerer.declareParams(decl.parameters, inst.params);
1449
1591
  params.push(...declared.params);
1450
- const body = [...declared.prologue];
1592
+ const body = [...receiverInit, ...declared.prologue];
1451
1593
  const bodyBlock = blockBodyOf(decl);
1452
1594
  if (bodyBlock) {
1453
1595
  body.push(...lowerer.lowerStmts(bodyBlock.statements));
1454
1596
  if (fnCtx.inferReturn) {
1455
1597
  bodyReturn = resolveInferredReturn(lowerer, inst, fnCtx.inferReturn, body, decl);
1598
+ inst.returnType = bodyReturn;
1456
1599
  }
1457
1600
  appendImplicitUndefinedReturn(lowerer, body, bodyReturn, locOf(decl));
1458
1601
  }
@@ -1466,6 +1609,7 @@ export function lowerGenericInstance(lowerer, info, inst) {
1466
1609
  if (value.type.kind === "void") {
1467
1610
  body.push({ kind: "exprStmt", expr: value, loc: locOf(decl.body) });
1468
1611
  bodyReturn = resolveInferredReturn(lowerer, inst, fnCtx.inferReturn, body, decl);
1612
+ inst.returnType = bodyReturn;
1469
1613
  appendImplicitUndefinedReturn(lowerer, body, bodyReturn, locOf(decl));
1470
1614
  }
1471
1615
  else {
@@ -1473,6 +1617,7 @@ export function lowerGenericInstance(lowerer, info, inst) {
1473
1617
  fnCtx.inferReturn.entries.push({ stmt, node: decl.body });
1474
1618
  body.push(stmt);
1475
1619
  bodyReturn = resolveInferredReturn(lowerer, inst, fnCtx.inferReturn, body, decl);
1620
+ inst.returnType = bodyReturn;
1476
1621
  }
1477
1622
  }
1478
1623
  else {
@@ -1490,6 +1635,8 @@ export function lowerGenericInstance(lowerer, info, inst) {
1490
1635
  }
1491
1636
  const fn = {
1492
1637
  name: inst.name,
1638
+ sourceName: info.baseName,
1639
+ ...(!isAsync && !decl.asteriskToken && (ts.isFunctionDeclaration(decl) || ts.isFunctionExpression(decl)) ? { ownsPrototype: true } : {}),
1493
1640
  params,
1494
1641
  returnType: bodyReturn,
1495
1642
  locals: lowerer.ctx.locals,
@@ -1509,6 +1656,7 @@ export function lowerGenericInstance(lowerer, info, inst) {
1509
1656
  lowerer.typeParamTsBindings = prevTsBindings;
1510
1657
  lowerer.implicitParamTypes = prevImplicit;
1511
1658
  lowerer.instantiationContext = prevContext;
1659
+ lowerer.localClassInstantiations.pop();
1512
1660
  lowerer.suppressStats = prevSuppress;
1513
1661
  }
1514
1662
  }
@@ -1524,14 +1672,15 @@ export function lowerGenericInstance(lowerer, info, inst) {
1524
1672
  * adds JS's undefined; DYN when returns disagree (the checked-dynamic
1525
1673
  * result slot — today's shape). Same-key recursion PINNED the fallback
1526
1674
  * type mid-lowering (callers already hold it), so a pinned instance
1527
- * keeps it and the wrap pass coerces every return to the pin. */
1675
+ * keeps it and the wrap pass coerces every return to the pin. Callers
1676
+ * store the settled type on their full instance; this narrower view
1677
+ * can be a structural copy in native builds. */
1528
1678
  function resolveInferredReturn(lowerer, inst, infer, body, decl) {
1529
1679
  // The conservative completion test appendImplicitUndefinedReturn uses:
1530
1680
  // a body whose last statement isn't a terminator may complete without
1531
1681
  // returning — JS answers undefined.
1532
1682
  const last = body[body.length - 1];
1533
1683
  const mayFallThrough = !last || !(last.kind === "return" || last.kind === "throw" || last.kind === "rethrow" || last.kind === "runtimeFence");
1534
- const valued = infer.entries.filter((e) => e.stmt.kind === "return" && e.stmt.value !== null && e.stmt.value !== undefined);
1535
1684
  const sawBare = mayFallThrough || infer.entries.some((e) => e.stmt.kind === "return" && (e.stmt.value === null || e.stmt.value === undefined));
1536
1685
  let final;
1537
1686
  if (inst.returnPinned) {
@@ -1539,43 +1688,46 @@ function resolveInferredReturn(lowerer, inst, infer, body, decl) {
1539
1688
  }
1540
1689
  else {
1541
1690
  const distinct = [];
1542
- for (const e of valued) {
1543
- if (!distinct.some((t) => typeEquals(t, e.stmt.value.type)))
1544
- distinct.push(e.stmt.value.type);
1691
+ for (const e of infer.entries) {
1692
+ if (e.stmt.kind !== "return" || e.stmt.value === null || e.stmt.value === undefined)
1693
+ continue;
1694
+ const type = e.stmt.value.type;
1695
+ if (!distinct.some((t) => typeEquals(t, type)))
1696
+ distinct.push(type);
1545
1697
  }
1546
1698
  if (distinct.length === 0) {
1547
1699
  final = DYN; // no valued return: JS completes with undefined — the dyn undefined, today's slot
1548
1700
  }
1549
1701
  else if (distinct.length === 1) {
1550
1702
  const t = distinct[0];
1551
- final = !sawBare ? t : t.kind === "dyn" ? DYN : (lowerer.withUndefinedArmOf(t) ?? DYN);
1703
+ final = isUnitType(t) ? DYN : !sawBare ? t : t.kind === "dyn" ? DYN : (lowerer.withUndefinedArmOf(t) ?? DYN);
1552
1704
  }
1553
1705
  else {
1554
1706
  final = DYN; // disagreeing returns: the checked-dynamic join
1555
1707
  }
1556
- inst.returnType = final;
1557
1708
  }
1558
1709
  // The wrap pass: settle every recorded return onto `final`, in place.
1710
+ // Write through the stored union arm: optional-field widening on a
1711
+ // local alias can otherwise introduce a record copy in native builds.
1559
1712
  for (const e of infer.entries) {
1560
1713
  if (e.stmt.kind !== "return")
1561
1714
  continue;
1562
- const st = e.stmt;
1563
1715
  const diagsBefore = lowerer.diags.length;
1564
1716
  try {
1565
- if (st.value === null || st.value === undefined) {
1717
+ if (e.stmt.value === null || e.stmt.value === undefined) {
1566
1718
  if (final.kind === "dyn")
1567
- st.value = dynUndefinedExpr(st.loc);
1719
+ e.stmt.value = dynUndefinedExpr(e.stmt.loc);
1568
1720
  else if (final.kind === "union") {
1569
- const wrapped = lowerer.wrappedUndefined(final, st.loc);
1721
+ const wrapped = lowerer.wrappedUndefined(final, e.stmt.loc);
1570
1722
  if (!wrapped) {
1571
1723
  lowerer.unsupported("SC1090", e.node ?? decl, `bare 'return' in a function whose inferred return type is '${lowerer.fmt(final)}'`);
1572
1724
  }
1573
- st.value = wrapped;
1725
+ e.stmt.value = wrapped;
1574
1726
  }
1575
1727
  // void final: bare return stands as-is
1576
1728
  }
1577
- else if (!typeEquals(st.value.type, final)) {
1578
- st.value = lowerer.coerceInto(e.node ?? decl, st.value, final);
1729
+ else if (!typeEquals(e.stmt.value.type, final)) {
1730
+ e.stmt.value = lowerer.coerceInto(e.node ?? decl, e.stmt.value, final);
1579
1731
  }
1580
1732
  }
1581
1733
  catch (err) {
@@ -1590,7 +1742,7 @@ function resolveInferredReturn(lowerer, inst, infer, body, decl) {
1590
1742
  lowerer.diags.push(...ice);
1591
1743
  lowerer.runtimeFences.push(...captured.filter((d) => d.code !== "SC9001"));
1592
1744
  const first = captured.find((d) => d.code !== "SC9001");
1593
- const mutable = st;
1745
+ const mutable = e.stmt;
1594
1746
  delete mutable["value"];
1595
1747
  mutable["kind"] = "runtimeFence";
1596
1748
  mutable["code"] = first?.code ?? "SC1090";
@@ -1848,10 +2000,12 @@ function broadPromiseParam(lowerer, type) {
1848
2000
  }
1849
2001
  /** The implicit-type-parameter slots of a JS function-like: parallel to
1850
2002
  * decl.parameters, the param SYMBOL where the slot is a bindable
1851
- * implicit-any param (identifier-named, no annotation/JSDoc type, not
1852
- * rest/optional/defaulted, never written), null elsewhere. Null overall
1853
- * when nothing qualifies — the declaration keeps today's path. */
1854
- export function implicitAnyParamSymbolsOf(lowerer, decl) {
2003
+ * implicit param (identifier-named, broad inferred/JSDoc type, not
2004
+ * rest/optional/defaulted, never written), null elsewhere. Package JS
2005
+ * methods may also specialize class parameters: JSDoc names a nominal
2006
+ * class even when the body accepts other objects with the same members.
2007
+ * Null overall when nothing qualifies — the declaration keeps its ABI. */
2008
+ export function implicitAnyParamSymbolsOf(lowerer, decl, classParams = false) {
1855
2009
  if (!decl.body)
1856
2010
  return null;
1857
2011
  if (decl.asteriskToken)
@@ -1877,7 +2031,9 @@ export function implicitAnyParamSymbolsOf(lowerer, decl) {
1877
2031
  const broadFunction = lowerer.checker.typeToString(t) === "Function";
1878
2032
  const broadArray = lowerer.checkerAnyArrayType(t);
1879
2033
  const broadPromise = broadPromiseParam(lowerer, t);
1880
- if ((t.flags & ts.TypeFlags.Any) === 0 && !broadFunction && !broadArray && !broadPromise)
2034
+ const declaredKind = classParams ? lowerer.mapTypeOf(t)?.kind : undefined;
2035
+ const classParam = classParams && (declaredKind === "object" || declaredKind === "array");
2036
+ if ((t.flags & ts.TypeFlags.Any) === 0 && !broadFunction && !broadArray && !broadPromise && !classParam)
1881
2037
  return null;
1882
2038
  const sym = lowerer.checker.getSymbolAtLocation(param.name);
1883
2039
  if (!sym)
@@ -1896,6 +2052,11 @@ export function implicitAnyParamSymbolsOf(lowerer, decl) {
1896
2052
  * selects return INFERENCE with DYN as the recursion pin. */
1897
2053
  function implicitDeclaredReturn(lowerer, info) {
1898
2054
  try {
2055
+ // Static JS helpers can accept a structurally compatible class despite
2056
+ // narrower JSDoc (for example a Vector2 target documented as Vector3).
2057
+ // Infer their result from the specialized body as well.
2058
+ if (info.member?.kind === "static" && info.decl.parameters.some((param, index) => info.implicitParams?.[index] && lowerer.mapTypeOf(lowerer.typeOf(param.name))?.kind === "object"))
2059
+ return null;
1899
2060
  const broadCallbackSymbols = new Set(info.decl.parameters.flatMap((param, index) => {
1900
2061
  const symbol = info.implicitParams?.[index];
1901
2062
  return symbol !== null && symbol !== undefined &&
@@ -1915,7 +2076,10 @@ function implicitDeclaredReturn(lowerer, info) {
1915
2076
  expression = expression.expression;
1916
2077
  if (ts.isCallExpression(expression) &&
1917
2078
  ts.isIdentifier(expression.expression) &&
1918
- broadCallbackSymbols.has(lowerer.checker.getSymbolAtLocation(expression.expression) ?? {})) {
2079
+ (() => {
2080
+ const symbol = lowerer.checker.getSymbolAtLocation(expression.expression);
2081
+ return symbol !== undefined && broadCallbackSymbols.has(symbol);
2082
+ })()) {
1919
2083
  returnsBroadCallback = true;
1920
2084
  return "stop";
1921
2085
  }
@@ -1930,7 +2094,12 @@ function implicitDeclaredReturn(lowerer, info) {
1930
2094
  const retTs = lowerer.checker.getReturnTypeOfSignature(declSig);
1931
2095
  if (retTs.flags & ts.TypeFlags.Any)
1932
2096
  return null;
2097
+ if (retTs.flags & (ts.TypeFlags.Null | ts.TypeFlags.Undefined))
2098
+ return DYN;
1933
2099
  if (lowerer.checker.isArrayType(retTs)) {
2100
+ if (info.decl.parameters.some((param, index) => info.implicitParams?.[index] &&
2101
+ lowerer.mapTypeOf(lowerer.typeOf(param.name))?.kind === "array"))
2102
+ return null;
1934
2103
  const elem = lowerer.checker.getTypeArguments(retTs)[0];
1935
2104
  // An implicit-any parameter poisons an inferred array result to
1936
2105
  // any[] even when this instance's body produces one concrete
@@ -1941,6 +2110,38 @@ function implicitDeclaredReturn(lowerer, info) {
1941
2110
  return null;
1942
2111
  }
1943
2112
  const mapped = lowerer.mapTypeOf(retTs);
2113
+ if (mapped?.kind === "symbol" && !hasExplicitJsDocReturn(info.decl))
2114
+ return null;
2115
+ if (mapped?.kind === "date" && !hasExplicitJsDocReturn(info.decl))
2116
+ return DYN;
2117
+ if (!hasExplicitJsDocReturn(info.decl) && info.decl.body) {
2118
+ let openReturn = false;
2119
+ ts.walkPreorder(info.decl.body, (node) => {
2120
+ if (node !== info.decl.body && ts.isFunctionLike(node))
2121
+ return "skip";
2122
+ if (!ts.isReturnStatement(node) || !node.expression || !ts.isIdentifier(node.expression))
2123
+ return undefined;
2124
+ const symbol = lowerer.resolveValueSymbol(node.expression);
2125
+ if (symbol && lowerer.checker.declarationsOf(symbol).some((decl) => ts.isVariableDeclaration(decl) && jsBindingHasOpenWrites(lowerer, decl)))
2126
+ openReturn = true;
2127
+ return undefined;
2128
+ });
2129
+ if (openReturn)
2130
+ return null;
2131
+ }
2132
+ // A JavaScript result inferred from an initial record can later
2133
+ // carry additional fields. Settle its representation from the
2134
+ // lowered returns instead of copying it back into that initial shape.
2135
+ const resultArms = mapped?.kind === "union" ? lowerer.unions.get(mapped.unionId)?.arms : mapped ? [mapped] : [];
2136
+ if (resultArms?.some((arm) => arm.kind === "record" || arm.kind === "object" || arm.kind === "classval") &&
2137
+ resultArms.every((arm) => isUnitType(arm) || arm.kind === "record" || arm.kind === "object" || arm.kind === "classval") &&
2138
+ !hasExplicitJsDocReturn(info.decl))
2139
+ return null;
2140
+ // Inferred variadic results carry runtime argument packs. Their
2141
+ // factory must retain the lowered callable rather than extracting a
2142
+ // fixed native signature from a checked value.
2143
+ if (mapped?.kind === "func" && mapped.rest === true && mapped.restAbi === undefined && !hasExplicitJsDocReturn(info.decl))
2144
+ return null;
1944
2145
  if (mapped !== null && promiseCarriesDyn(lowerer, mapped) && !hasExplicitJsDocReturn(info.decl))
1945
2146
  return null;
1946
2147
  return mapped;
@@ -1972,6 +2173,54 @@ function bindableImplicitIr(t) {
1972
2173
  t.kind !== "void" && t.kind !== "dyn" && t.kind !== "jsval" &&
1973
2174
  t.kind !== "caught" && t.kind !== "undefinedT" && t.kind !== "nullT");
1974
2175
  }
2176
+ /** A represented binding or direct callable result can be wider than the
2177
+ * checker's inferred shape. Preserve that boundary when specializing JS. */
2178
+ function storedImplicitArgumentType(lowerer, arg) {
2179
+ while (ts.isParenthesizedExpression(arg))
2180
+ arg = arg.expression;
2181
+ if (isJsSourceFile(arg.getSourceFile()) && (ts.isArrowFunction(arg) || ts.isFunctionExpression(arg))) {
2182
+ const saved = lowerer.diagSink;
2183
+ const diagnostics = [];
2184
+ lowerer.diagSink = diagnostics;
2185
+ let value;
2186
+ try {
2187
+ value = tryLowerExpression(lowerer, arg);
2188
+ }
2189
+ finally {
2190
+ lowerer.diagSink = saved;
2191
+ }
2192
+ // Direct inferred helpers can receive native callbacks even when their
2193
+ // result is an opaque handle that cannot cross checked storage.
2194
+ if (diagnostics.length === 0 && value?.type.kind === "func")
2195
+ return value.type;
2196
+ }
2197
+ if (arg.kind === ts.SyntaxKind.ThisKeyword)
2198
+ return lowerer.resolveThis()?.type ?? null;
2199
+ if (ts.isAwaitExpression(arg)) {
2200
+ const awaited = storedImplicitArgumentType(lowerer, arg.expression);
2201
+ return awaited?.kind === "promise" ? awaited.inner : awaited;
2202
+ }
2203
+ if (ts.isObjectLiteralExpression(arg) && isJsSourceFile(arg.getSourceFile()) &&
2204
+ (arg.properties.length === 0 || arg.properties.some((property) => ts.isMethodDeclaration(property) || ts.isAccessor(property) ||
2205
+ !ts.isSpreadAssignment(property) && property.name !== undefined && ts.isComputedPropertyName(property.name))))
2206
+ return DYN;
2207
+ if (ts.isIdentifier(arg))
2208
+ return lowerer.peekLocal(arg)?.type ?? lowerer.globalOf(arg)?.type ?? null;
2209
+ if (ts.isCallExpression(arg) && ts.isIdentifier(arg.expression)) {
2210
+ if (isJsSourceFile(arg.getSourceFile())) {
2211
+ const represented = tryLowerExpression(lowerer, arg);
2212
+ if (represented?.type.kind === "dyn" || represented?.type.kind === "func")
2213
+ return represented.type;
2214
+ }
2215
+ const callee = storedImplicitArgumentType(lowerer, arg.expression);
2216
+ if (callee?.kind === "dyn")
2217
+ return DYN;
2218
+ if (callee?.kind === "func")
2219
+ return callee.ret;
2220
+ return lowerer.fnSigOf(arg.expression)?.returnType ?? null;
2221
+ }
2222
+ return null;
2223
+ }
1975
2224
  /** The instance a CALL of an implicit-any function-like names: each
1976
2225
  * bindable implicit param takes the call's WIDENED argument checker type
1977
2226
  * when it maps statically (DYN otherwise — today's slot), typed params
@@ -1994,19 +2243,74 @@ export function implicitCallInstance(lowerer, call, info) {
1994
2243
  bound = declared.type;
1995
2244
  const arg = call.arguments[i];
1996
2245
  if (arg && !ts.isSpreadElement(arg)) {
1997
- const runtimeLocal = ts.isIdentifier(arg) ? lowerer.peekLocal(arg) : null;
1998
- if (runtimeLocal?.type.kind === "dyn") {
2246
+ const stored = storedImplicitArgumentType(lowerer, arg);
2247
+ if (stored?.kind === "dyn") {
1999
2248
  bound = DYN;
2000
2249
  argTypes.set(sym, lowerer.checker.getUnknownType());
2001
2250
  shapes.push({ type: bound, mode: "required" });
2002
2251
  return;
2003
2252
  }
2253
+ // A represented native array must keep its storage when a direct
2254
+ // inferred helper receives it. Re-boxing a checker-any array would
2255
+ // copy it, losing writes (and attempting to read unfilled slots).
2256
+ if (stored?.kind === "array") {
2257
+ argTypes.set(sym, lowerer.typeOf(arg));
2258
+ shapes.push({ type: stored, mode: "required" });
2259
+ return;
2260
+ }
2261
+ if (stored?.kind === "func") {
2262
+ // The lowered closure may have an inferred JS destructuring
2263
+ // parameter widened from the checker's exact tuple to dyn.
2264
+ // Preserve that signature throughout the specialization.
2265
+ const checkerType = lowerer.mapTypeOf(lowerer.typeOf(arg));
2266
+ argTypes.set(sym, checkerType && typeEquals(checkerType, stored)
2267
+ ? lowerer.typeOf(arg) : lowerer.checker.getUnknownType());
2268
+ shapes.push({ type: stored, mode: "required" });
2269
+ return;
2270
+ }
2004
2271
  // The argument's own checker type, literal-widened ('add' binds
2005
2272
  // string) — typeOf consults the ACTIVE instance's bindings, so a
2006
2273
  // bound param forwarded into another implicit call transitively
2007
2274
  // instantiates it (this._initCommandGroup(command)).
2008
2275
  const t = lowerer.checker.getBaseTypeOfLiteralType(lowerer.typeOf(arg));
2009
- const mapped = lowerer.mapTypeOf(t) ?? dynFallbackType(lowerer, arg, t);
2276
+ const mapped = (neverTaintedJsType(lowerer, arg, t) ? null : lowerer.mapTypeOf(t)) ?? dynFallbackType(lowerer, arg, t);
2277
+ if (isJsSourceFile(arg.getSourceFile()) && ts.isArrayLiteralExpression(arg) && mapped?.kind === "array" &&
2278
+ (mapped.elem.kind === "classval" || mapped.elem.kind === "union" &&
2279
+ lowerer.unions.get(mapped.elem.unionId)?.arms.every((arm) => arm.kind === "classval"))) {
2280
+ argTypes.set(sym, lowerer.checker.getUnknownType());
2281
+ shapes.push({ type: DYN, mode: "required" });
2282
+ return;
2283
+ }
2284
+ // JavaScript arguments-based callables travel as checked functions.
2285
+ // Specializing a parameter to the inferred rest signature would
2286
+ // require extracting a native variadic ABI that the value does not
2287
+ // expose. Its checked invocation preserves the complete argument pack.
2288
+ if (mapped?.kind === "func" && mapped.rest === true && mapped.restAbi === undefined) {
2289
+ argTypes.set(sym, lowerer.checker.getUnknownType());
2290
+ shapes.push({ type: DYN, mode: "required" });
2291
+ return;
2292
+ }
2293
+ // JS inference can absorb heterogeneous loop values into `{}`.
2294
+ // That checker supertype is not an empty-record runtime layout:
2295
+ // preserve represented arms through the checked boundary instead
2296
+ // of specializing a call to a union that would discard them.
2297
+ if (isJsSourceFile(arg.getSourceFile()) && mapped?.kind === "func" && !lowerer.dynConvertible(mapped)) {
2298
+ argTypes.set(sym, lowerer.checker.getUnknownType());
2299
+ shapes.push({ type: DYN, mode: "required" });
2300
+ return;
2301
+ }
2302
+ const mappedArms = mapped?.kind === "union" ? lowerer.unions.get(mapped.unionId)?.arms ?? [] : mapped ? [mapped] : [];
2303
+ const hasTopObject = mappedArms.some((arm) => {
2304
+ const shape = arm.kind === "record" ? lowerer.shapes.get(arm.shapeId) : undefined;
2305
+ return shape && !shape.tuple && !shape.indexValue && shape.fields.length === 0;
2306
+ });
2307
+ if (stored?.kind === "union" && hasTopObject && lowerer.dynConvertible(stored) &&
2308
+ lowerer.unions.get(stored.unionId)?.arms.some((arm) => !isUnitType(arm) &&
2309
+ !mappedArms.some((target) => lowerer.widthLiftPlan(arm, target) !== null))) {
2310
+ argTypes.set(sym, lowerer.checker.getUnknownType());
2311
+ shapes.push({ type: DYN, mode: "required" });
2312
+ return;
2313
+ }
2010
2314
  if (ts.isArrowFunction(arg) &&
2011
2315
  arg.type === undefined &&
2012
2316
  mapped?.kind === "func" &&
@@ -2031,15 +2335,32 @@ export function implicitCallInstance(lowerer, call, info) {
2031
2335
  /** The all-dyn DEFAULT instance — today's compiled body exactly: what a
2032
2336
  * VALUE reference of an implicit-any function names (indirect calls
2033
2337
  * carry no per-site types to bind). */
2034
- function implicitDefaultInstance(lowerer, blame, info) {
2338
+ export function implicitDefaultInstance(lowerer, blame, info) {
2035
2339
  const shapes = info.decl.parameters.map((param, i) => info.implicitParams[i] ? { type: DYN, mode: "required" } : lowerer.paramShape(param));
2036
- return internImplicitInstance(lowerer, blame, info, shapes, new Map());
2340
+ const argTypes = new Map();
2341
+ // Newly bindable nominal class parameters must not retain their JSDoc
2342
+ // receiver type in the checked fallback. Keep existing broad JS inference.
2343
+ for (let i = 0; i < info.decl.parameters.length; i++) {
2344
+ const symbol = info.implicitParams?.[i];
2345
+ const kind = lowerer.mapTypeOf(lowerer.typeOf(info.decl.parameters[i].name))?.kind;
2346
+ if (symbol && (kind === "object" || kind === "array")) {
2347
+ argTypes.set(symbol, lowerer.checker.getUnknownType());
2348
+ }
2349
+ }
2350
+ return internImplicitInstance(lowerer, blame, info, shapes, argTypes);
2037
2351
  }
2038
2352
  function internImplicitInstance(lowerer, blame, info, shapes, argTypes) {
2039
2353
  const key = shapes.map((s) => typeKey(s.type)).join(",");
2040
2354
  let inst = info.instances.get(key);
2041
- if (inst)
2355
+ if (inst?.implicitState === "failed")
2356
+ lowerer.unsupported("SC1090", blame, `the failed specialization of '${info.baseName}'`);
2357
+ if (inst) {
2358
+ // A recursive caller has observed this ABI before inference settles.
2359
+ // Keep the promised return slot and coerce the completed body's returns.
2360
+ if (inst.implicitState === "lowering")
2361
+ inst.returnPinned = true;
2042
2362
  return inst;
2363
+ }
2043
2364
  if (info.instances.size >= MAX_GENERIC_INSTANCES) {
2044
2365
  lowerer.unsupported("SC1090", blame, `unbounded implicit-any instantiation ('${info.baseName}' exceeded ` +
2045
2366
  `${MAX_GENERIC_INSTANCES} instances — polymorphic recursion?)`);
@@ -2065,11 +2386,15 @@ function internImplicitInstance(lowerer, blame, info, shapes, argTypes) {
2065
2386
  ...(declared === null ? { implicitInferReturn: true } : {}),
2066
2387
  };
2067
2388
  info.instances.set(key, inst);
2068
- // EAGER lowering (nested, the lambda discipline): the call site needs
2069
- // the settled return type NOW. A body-level poison (a fenced parameter
2070
- // form) skips the function like lowerFunction's rule — calls then meet
2071
- // the pinned signature over a missing body, which the linker never
2072
- // sees because the poison also fenced the call statement.
2389
+ // Eager lowering settles the return ABI before callers use it. A failed
2390
+ // JS body must still have a throwing implementation: later references
2391
+ // (including recursive ones) can already hold its cached signature.
2392
+ const diagsBefore = lowerer.diags.length;
2393
+ // The instance is cached even when a receiver probe requested it.
2394
+ // Its body must retain statement fences instead of dropping failures
2395
+ // into that probe's temporary diagnostic sink and caching empty code.
2396
+ const previousSink = lowerer.diagSink;
2397
+ lowerer.diagSink = null;
2073
2398
  try {
2074
2399
  // Implicit-any instances lower EAGERLY at the call site so their
2075
2400
  // inferred return type is available immediately. They therefore do
@@ -2087,8 +2412,20 @@ function internImplicitInstance(lowerer, blame, info, shapes, argTypes) {
2087
2412
  catch (e) {
2088
2413
  if (!(e instanceof PoisonError))
2089
2414
  throw e;
2090
- inst.implicitState = "done";
2091
- throw e;
2415
+ inst.implicitState = "failed";
2416
+ const types = shapes.map((shape) => shape.type);
2417
+ if (info.member?.kind === "method")
2418
+ types.unshift({ kind: "object", className: info.member.cls.def.name });
2419
+ const fn = lowerer.deferToRuntimeFence(diagsBefore, info.decl, {
2420
+ kind: "function", name: inst.name, returnType: inst.returnType,
2421
+ params: types.map((type, index) => ({ localId: `p.${index}`, name: `p${index}`, type })),
2422
+ });
2423
+ if (!fn)
2424
+ throw e;
2425
+ lowerer.implicitFns.push(fn);
2426
+ }
2427
+ finally {
2428
+ lowerer.diagSink = previousSink;
2092
2429
  }
2093
2430
  inst.implicitState = "done";
2094
2431
  return inst;
@@ -2194,11 +2531,11 @@ export function implicitLocalFnInfoOf(lowerer, decl, fnNode) {
2194
2531
  const implicit = implicitAnyParamSymbolsOf(lowerer, fnNode);
2195
2532
  if (!implicit)
2196
2533
  lowerer.unsupported("SC1090", fnNode, "this function form"); // defensive: the probe proved it
2197
- const stmt = decl.parent.parent;
2534
+ const stmt = decl.parent?.parent;
2198
2535
  const info = {
2199
2536
  decl: fnNode,
2200
2537
  baseName: name,
2201
- qualifiedName: lowerer.qualify(decl.getSourceFile(), nsPathPrefix(stmt, decl) + `${name}%l${decl.getStart()}`),
2538
+ qualifiedName: lowerer.qualify(decl.getSourceFile(), nsPathPrefix(stmt ?? decl, decl) + `${name}%l${decl.getStart()}`),
2202
2539
  typeParams: [],
2203
2540
  instances: new Map(),
2204
2541
  implicitParams: implicit,
@@ -2409,6 +2746,7 @@ function makeTimerArgsThunk(lowerer, cbNode, argNodes, what, loc) {
2409
2746
  kind: "dynCall",
2410
2747
  callee: { kind: "varRef", localId: "f.0", type: DYN, loc },
2411
2748
  calleeName: "callback",
2749
+ receiver: { kind: "libCall", fn: "dyn.this", args: [], type: DYN, loc },
2412
2750
  args: args.map((_, i) => ({ kind: "varRef", localId: `a${i}.0`, type: DYN, loc })),
2413
2751
  type: DYN,
2414
2752
  loc,
@@ -2506,7 +2844,15 @@ export function lowerTimersMemberCall(lowerer, expr, member, loc) {
2506
2844
  if (expr.arguments.length !== 1) {
2507
2845
  lowerer.noLowering(`clearTimeout with ${expr.arguments.length} arguments`, expr);
2508
2846
  }
2509
- const handle = lowerer.lowerExpr(expr.arguments[0]);
2847
+ let handle = lowerer.lowerExpr(expr.arguments[0]);
2848
+ if (handle.type.kind === "dyn" && isJsSourceFile(expr.getSourceFile())) {
2849
+ const stored = lowerer.declareHiddenLocal("%timer.clear", DYN);
2850
+ const ref = varRef(stored.id, DYN, loc);
2851
+ handle = { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: stored.id, init: handle, loc }], result: {
2852
+ kind: "ternary", cond: { kind: "dynTest", test: "number", value: ref, type: BOOL, loc },
2853
+ then: lowerer.coerceInto(expr.arguments[0], ref, F64), else_: numLit(0, loc), type: F64, loc,
2854
+ }, type: F64, loc };
2855
+ }
2510
2856
  if (handle.type.kind !== "f64") {
2511
2857
  lowerer.noLowering(`clearTimeout of '${lowerer.fmt(handle.type)}' handles`, expr.arguments[0], "the handle is the Timeout setTimeout returned (narrow 'Timeout | null' first)");
2512
2858
  }
@@ -2573,7 +2919,12 @@ export function lowerTimersMemberCall(lowerer, expr, member, loc) {
2573
2919
  return null;
2574
2920
  }
2575
2921
  function ffiSourceParams(binding) {
2576
- return binding.params.filter((param) => !isFfiContextParam(param));
2922
+ const params = [];
2923
+ for (const param of binding.params) {
2924
+ if (!isFfiContextParam(param))
2925
+ params.push(param);
2926
+ }
2927
+ return params;
2577
2928
  }
2578
2929
  function ffiParamDisplay(param) {
2579
2930
  return isFfiCallbackParam(param)
@@ -2590,7 +2941,11 @@ function ffiCallbackInputDiagnostic(lowerer, descriptor, callbackType) {
2590
2941
  const signatures = lowerer.checker.getCallSignatures(callbackType);
2591
2942
  if (signatures.length !== 1)
2592
2943
  return null;
2593
- const nativeParams = descriptor.callback.params.filter((param) => !isFfiContextParam(param));
2944
+ const nativeParams = [];
2945
+ for (const param of descriptor.callback.params) {
2946
+ if (!isFfiContextParam(param))
2947
+ nativeParams.push(param);
2948
+ }
2594
2949
  let nativeIndex = 0;
2595
2950
  const params = signatures[0].getParameters();
2596
2951
  for (let i = 0; i < params.length; i++) {
@@ -2608,12 +2963,13 @@ function ffiCallbackInputDiagnostic(lowerer, descriptor, callbackType) {
2608
2963
  }
2609
2964
  if (nativeClass === "bytes")
2610
2965
  continue;
2611
- const domain = nativeClass === "bool"
2966
+ const wide = nativeClass === "i64" || nativeClass === "u64" || nativeClass === "pointer";
2967
+ const domain = wide ? "bigint" : nativeClass === "bool"
2612
2968
  ? "boolean"
2613
2969
  : nativeClass === "cstring" || nativeClass === "string"
2614
2970
  ? "string"
2615
2971
  : "number";
2616
- const coversDomain = nativeClass === "bool"
2972
+ const coversDomain = wide ? (paramType.flags & ts.TypeFlags.BigInt) !== 0 : nativeClass === "bool"
2617
2973
  ? (paramType.flags & ts.TypeFlags.Boolean) !== 0
2618
2974
  : nativeClass === "cstring" || nativeClass === "string"
2619
2975
  ? (paramType.flags & ts.TypeFlags.String) !== 0
@@ -2636,8 +2992,9 @@ function ffiCallbackInputDiagnostic(lowerer, descriptor, callbackType) {
2636
2992
  function ffiReturnDomainDiagnostic(lowerer, nativeClass, returnType) {
2637
2993
  if (nativeClass === "void")
2638
2994
  return null;
2639
- const domain = nativeClass === "bool" ? "boolean" : "number";
2640
- const coversDomain = nativeClass === "bool"
2995
+ const wide = nativeClass === "i64" || nativeClass === "u64" || nativeClass === "pointer";
2996
+ const domain = wide ? "bigint" : nativeClass === "bool" ? "boolean" : "number";
2997
+ const coversDomain = wide ? (returnType.flags & ts.TypeFlags.BigInt) !== 0 : nativeClass === "bool"
2641
2998
  ? (returnType.flags & ts.TypeFlags.Boolean) !== 0
2642
2999
  : (returnType.flags & ts.TypeFlags.Number) !== 0;
2643
3000
  return coversDomain
@@ -2745,7 +3102,7 @@ function libraryCallbackOwnsFile(lowerer, file) {
2745
3102
  export function validateFfiImports(lowerer) {
2746
3103
  const diagnostics = [];
2747
3104
  const symbolsByName = new Map();
2748
- const configuredNames = new Set(lowerer.ffiImports.map((binding) => binding.name));
3105
+ const configuredNames = new Set(lowerer.ffiImports.filter(binding => binding.library === undefined).map((binding) => binding.name));
2749
3106
  const candidates = new Map();
2750
3107
  if (configuredNames.size === 0)
2751
3108
  return { diagnostics, symbolsByName };
@@ -2775,6 +3132,8 @@ export function validateFfiImports(lowerer) {
2775
3132
  });
2776
3133
  }
2777
3134
  for (const binding of lowerer.ffiImports) {
3135
+ if (binding.library !== undefined)
3136
+ continue;
2778
3137
  const bySymbol = candidates.get(binding.name);
2779
3138
  if (bySymbol === undefined || bySymbol.size === 0) {
2780
3139
  // A native-manifest binding with no declaration is a broken build
@@ -2822,6 +3181,8 @@ export function lowerFfiCall(lowerer, expr) {
2822
3181
  if (!ts.isIdentifier(expr.expression))
2823
3182
  return null;
2824
3183
  const binding = lowerer.ffiImportsByName.get(expr.expression.text);
3184
+ if (binding?.library !== undefined)
3185
+ return null;
2825
3186
  if (binding === undefined) {
2826
3187
  // LIBRARY mode with a declared callback surface: a CALL of a
2827
3188
  // program-authored signature-only ambient function that names no
@@ -2855,7 +3216,8 @@ export function lowerFfiCall(lowerer, expr) {
2855
3216
  lowerer.pushDiag(signatureFlavor(binding.name, detail, loc));
2856
3217
  throw new PoisonError();
2857
3218
  };
2858
- const symbol = lowerer.resolveValueSymbol(expr.expression) ??
3219
+ const symbol = lowerer.resolveValueSymbol(expr.expression);
3220
+ if (!symbol)
2859
3221
  bindingError("the call has no resolved TypeScript symbol");
2860
3222
  if (lowerer.ffiBindingSymbols !== null) {
2861
3223
  const validSymbols = lowerer.ffiBindingSymbols.get(binding.name);
@@ -2938,7 +3300,7 @@ export function lowerFfiCall(lowerer, expr) {
2938
3300
  }
2939
3301
  // An inline function value at a RELEASE site can never match:
2940
3302
  // lifted lambdas always carry a captures list (even an empty one),
2941
- // so both backends mint a fresh closure per evaluation of the
3303
+ // so the backend creates a fresh closure per evaluation of the
2942
3304
  // expression — the release argument is a pointer no registration
2943
3305
  // holds, a guaranteed runtime trap. Declared functions stay valid
2944
3306
  // here — their value is the interned immortal closure (captures
@@ -3017,6 +3379,14 @@ function lowerProjectedBuiltinCall(lowerer, expr, bi, loc) {
3017
3379
  }
3018
3380
  export function lowerCall(lowerer, expr) {
3019
3381
  const loc = locOf(expr);
3382
+ // Object's checker return type is `any`. Claim known object inputs
3383
+ // before generic checked-dynamic dispatch tries to load the constructor.
3384
+ if (ts.isIdentifier(expr.expression) && expr.expression.text === "Object" &&
3385
+ lowerer.isStdlibGlobal(expr.expression, "Object")) {
3386
+ const object = lowerObjectConstructor(lowerer, expr.arguments, loc);
3387
+ if (object)
3388
+ return object;
3389
+ }
3020
3390
  // A call whose chain ROOTS at an ambient-undefined name (`declare
3021
3391
  // const value: Y | undefined; value?.foo("a")`, `declare function
3022
3392
  // chain...; chain(o).mapValues(f).value()`, a trap binding's read):
@@ -3126,7 +3496,7 @@ export function lowerCall(lowerer, expr) {
3126
3496
  // `a?.m()` (the token on the member access). The handled markers keep
3127
3497
  // the chain lowering's re-entrant dispatch from looping.
3128
3498
  if ((expr.questionDotToken && !lowerer.chainHandled.has(expr)) ||
3129
- (ts.isPropertyAccessExpression(expr.expression) &&
3499
+ ((ts.isPropertyAccessExpression(expr.expression) || ts.isElementAccessExpression(expr.expression)) &&
3130
3500
  expr.expression.questionDotToken &&
3131
3501
  !lowerer.chainHandled.has(expr.expression))) {
3132
3502
  return lowerer.lowerOptionalChain(expr);
@@ -3135,6 +3505,9 @@ export function lowerCall(lowerer, expr) {
3135
3505
  // top-level statement (its field-initializer ordering lives there);
3136
3506
  // any other position would misorder initialization — rejected.
3137
3507
  if (expr.expression.kind === ts.SyntaxKind.SuperKeyword) {
3508
+ const superCall = lowerer.ctx.superCall;
3509
+ if (superCall)
3510
+ return superCall(expr);
3138
3511
  lowerer.unsupported("SC1090", expr, "super() calls anywhere but as a top-level constructor statement");
3139
3512
  }
3140
3513
  // super.method(...): a DIRECT (never virtual) call of the base chain's
@@ -3145,6 +3518,18 @@ export function lowerCall(lowerer, expr) {
3145
3518
  }
3146
3519
  const consoleMember = lowerer.consoleCallMember(expr);
3147
3520
  if (consoleMember !== null) {
3521
+ // A namespace returned by user code must evaluate before the log
3522
+ // arguments. Only the global and literal builtin require plumbing
3523
+ // have no receiver evaluation to preserve.
3524
+ const access = ts.isPropertyAccessExpression(expr.expression) ? expr.expression : null;
3525
+ const created = access && ts.isCallExpression(access.expression) ? createRequireSpecOf(lowerer, access.expression) : null;
3526
+ const receiver = access && !lowerer.isStdlibGlobal(access.expression, "console") &&
3527
+ requireSpecOf(access.expression) === null &&
3528
+ created?.spec !== "node:console" && created?.spec !== "console"
3529
+ ? lowerer.lowerExpr(access.expression) : null;
3530
+ const withReceiver = (result) => receiver === null ? result : {
3531
+ kind: "seqExpr", stmts: [{ kind: "exprStmt", expr: receiver, loc }], result, type: result.type, loc,
3532
+ };
3148
3533
  // console.log/info/debug write stdout; console.error and console.warn
3149
3534
  // are one stream in Node (warn IS error, info and debug ARE log) and
3150
3535
  // write stderr with the exact same formatting. Node's formatter is
@@ -3166,13 +3551,13 @@ export function lowerCall(lowerer, expr) {
3166
3551
  (ts.isStringLiteral(expr.arguments[0]) || ts.isNoSubstitutionTemplateLiteral(expr.arguments[0])) &&
3167
3552
  /%[sdifjoOc%]/.test(expr.arguments[0].text)) {
3168
3553
  const formatted = lowerFormatCall(lowerer, expr, loc, false);
3169
- return {
3554
+ return withReceiver({
3170
3555
  kind: "intrinsic",
3171
3556
  name: stdoutMember ? "console.log" : "console.error",
3172
3557
  args: [formatted],
3173
3558
  type: VOID,
3174
3559
  loc,
3175
- };
3560
+ });
3176
3561
  }
3177
3562
  const args = expr.arguments.map((a) => {
3178
3563
  const lowered = lowerer.lowerExpr(a);
@@ -3233,13 +3618,20 @@ export function lowerCall(lowerer, expr) {
3233
3618
  // render fence honestly with the reason.
3234
3619
  return lowerConsoleInspectArg(lowerer, a, lowered, surface, loc);
3235
3620
  });
3236
- return {
3621
+ return withReceiver({
3237
3622
  kind: "intrinsic",
3238
3623
  name: stdoutMember ? "console.log" : "console.error",
3239
3624
  args,
3240
3625
  type: VOID,
3241
3626
  loc,
3242
- };
3627
+ });
3628
+ }
3629
+ if (ts.isPropertyAccessExpression(expr.expression) &&
3630
+ TIMER_MODULE_MEMBERS.has(expr.expression.name.text) &&
3631
+ lowerer.stdlibGlobalMember(expr.expression, "globalThis") === expr.expression.name.text) {
3632
+ const served = lowerTimersMemberCall(lowerer, expr, expr.expression.name.text, loc);
3633
+ if (served)
3634
+ return served;
3243
3635
  }
3244
3636
  // The timer globals — setTimeout/clearTimeout, setInterval/
3245
3637
  // clearInterval, setImmediate/clearImmediate. Provenance-checked (a
@@ -3383,40 +3775,24 @@ export function lowerCall(lowerer, expr) {
3383
3775
  // Provenance-checked like setTimeout; zero-arg forms are the JS
3384
3776
  // constants ("", false, 0). Wrapper objects stay fenced except where
3385
3777
  // the receiver is immediately converted by a direct String method call.
3386
- if (ts.isIdentifier(expr.expression) &&
3387
- expr.expression.text === "BigInt" &&
3388
- lowerer.isStdlibSymbol(lowerer.resolveValueSymbol(expr.expression) ?? undefined)) {
3778
+ if (lowerer.isStdlibGlobal(expr.expression, "BigInt")) {
3389
3779
  if (expr.arguments.length !== 1) {
3390
3780
  lowerer.noLowering(`BigInt with ${expr.arguments.length} arguments`, expr);
3391
3781
  }
3392
3782
  const argNode = expr.arguments[0];
3393
- const arg = lowerer.lowerExpr(argNode);
3394
- if (arg.type.kind === "bigint")
3395
- return arg;
3396
- if (arg.type.kind === "string") {
3397
- return { kind: "libCall", fn: "bigint.parse", args: [arg], type: BIGINT_T, loc };
3398
- }
3399
- if (arg.type.kind === "f64") {
3400
- return { kind: "libCall", fn: "bigint.fromF64", args: [arg], type: BIGINT_T, loc };
3401
- }
3402
- if (arg.type.kind === "bool") {
3403
- return {
3404
- kind: "ternary",
3405
- cond: arg,
3406
- then: { kind: "libCall", fn: "bigint.parse", args: [{ kind: "strLit", value: "1", type: STRING, loc }], type: BIGINT_T, loc },
3407
- else_: { kind: "libCall", fn: "bigint.parse", args: [{ kind: "strLit", value: "0", type: STRING, loc }], type: BIGINT_T, loc },
3408
- type: BIGINT_T,
3409
- loc,
3410
- };
3411
- }
3783
+ // Captured optional storage can change after TypeScript's guard.
3784
+ // BigInt consumes the stored value, including its nullish tag.
3785
+ const arg = optionalCallValue(lowerer, argNode) ?? lowerer.lowerExpr(argNode);
3786
+ const converted = lowerBigIntConstructorValue(lowerer, arg, loc);
3787
+ if (converted)
3788
+ return converted;
3412
3789
  lowerer.noLowering(`BigInt of ${lowerer.fmt(arg.type)} values`, argNode, "string, number, boolean, and bigint arguments are supported");
3413
3790
  }
3414
- if (ts.isIdentifier(expr.expression) &&
3415
- (expr.expression.text === "String" ||
3416
- expr.expression.text === "Boolean" ||
3417
- expr.expression.text === "Number") &&
3418
- lowerer.isStdlibSymbol(lowerer.resolveValueSymbol(expr.expression) ?? undefined)) {
3419
- const name = expr.expression.text;
3791
+ if (lowerer.isStdlibGlobal(expr.expression, "String") ||
3792
+ lowerer.isStdlibGlobal(expr.expression, "Boolean") ||
3793
+ lowerer.isStdlibGlobal(expr.expression, "Number")) {
3794
+ const name = lowerer.isStdlibGlobal(expr.expression, "String") ? "String" :
3795
+ lowerer.isStdlibGlobal(expr.expression, "Boolean") ? "Boolean" : "Number";
3420
3796
  if (expr.arguments.length > 1) {
3421
3797
  lowerer.noLowering(`${name} with ${expr.arguments.length} arguments`, expr);
3422
3798
  }
@@ -3446,6 +3822,10 @@ export function lowerCall(lowerer, expr) {
3446
3822
  if (name === "Number")
3447
3823
  return lowerNumberConstructorValue(lowerer, argNode, loc);
3448
3824
  const arg = lowerer.lowerExpr(argNode);
3825
+ if (name === "String" && (arg.type.kind === "dyn" || arg.type.kind === "union" &&
3826
+ lowerer.unions.get(arg.type.unionId)?.arms.some((arm) => arm.kind === "symbol") && lowerer.dynConvertible(arg.type))) {
3827
+ return { kind: "libCall", fn: "dyn.stringConstructor", args: [lowerer.coerceToExpected(arg, DYN)], type: STRING, loc };
3828
+ }
3449
3829
  if (name === "String")
3450
3830
  return lowerer.ensureString(arg, argNode);
3451
3831
  }
@@ -3463,6 +3843,30 @@ export function lowerCall(lowerer, expr) {
3463
3843
  const code = lowerer.lowerExprExpecting(expr.arguments[0], STRING);
3464
3844
  return { kind: "libCall", fn: "island.eval", args: [code], type: STRING, loc };
3465
3845
  }
3846
+ // Computed calls preserve their evaluated receiver just like dotted
3847
+ // calls, including when the property is keyed by a native symbol.
3848
+ if (ts.isElementAccessExpression(expr.expression) && !lowerer.chainBlocked(expr, expr.expression)) {
3849
+ const access = expr.expression;
3850
+ lowerer.fenceStaticResponseMember(access, "call");
3851
+ lowerer.fenceStaticHeadersMember(access, "call");
3852
+ lowerer.fenceStaticReadableStreamMember(access, "call");
3853
+ const source = tryLowerExpression(lowerer, access.expression);
3854
+ if (source && (source.type.kind === "dyn" || source.type.kind === "func" ||
3855
+ (source.type.kind === "map" || source.type.kind === "set") && lowerer.dynConvertible(source.type) || isDynTypedRefType(source.type) &&
3856
+ lowerer.foldedStringKeyOf(access.argumentExpression) === null &&
3857
+ lowerer.mapTypeOf(lowerer.typeOf(access.argumentExpression))?.kind !== "symbol")) {
3858
+ const local = lowerer.declareHiddenLocal("%computedReceiver", DYN);
3859
+ const receiver = varRef(local.id, DYN, loc);
3860
+ const key = lowerer.lowerExprExpecting(access.argumentExpression, DYN);
3861
+ const callee = { kind: "dynKeyGet", value: receiver, key, type: DYN, loc };
3862
+ const args = expr.arguments.map((arg) => lowerer.lowerExprExpecting(ts.isSpreadElement(arg) ? arg.expression : arg, DYN));
3863
+ const spreads = expr.arguments.flatMap((arg, index) => ts.isSpreadElement(arg) ? [{ arg: index, what: arg.expression.getText() }] : []);
3864
+ return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id, init: lowerer.coerceToExpected(source, DYN), loc }], result: {
3865
+ kind: "dynCall", callee, receiver, calleeName: access.getText(), args,
3866
+ ...(spreads.length > 0 ? { spreads } : {}), type: DYN, loc,
3867
+ }, type: DYN, loc };
3868
+ }
3869
+ }
3466
3870
  // Island calls. A property-access callee whose receiver is an 'any'
3467
3871
  // value is an engine method call (this = receiver, JS-exact); any other
3468
3872
  // 'any'-typed callee is an engine function call. Arguments marshal in;
@@ -3851,6 +4255,7 @@ export function lowerCall(lowerer, expr) {
3851
4255
  // string-only argument rule.
3852
4256
  if ((expr.expression.text === "encodeURIComponent" ||
3853
4257
  expr.expression.text === "encodeURI" ||
4258
+ expr.expression.text === "decodeURI" ||
3854
4259
  expr.expression.text === "decodeURIComponent") &&
3855
4260
  lowerer.isStdlibSymbol(lowerer.resolveValueSymbol(expr.expression) ?? undefined)) {
3856
4261
  const name = expr.expression.text;
@@ -3859,10 +4264,10 @@ export function lowerCall(lowerer, expr) {
3859
4264
  }
3860
4265
  const loc = locOf(expr);
3861
4266
  const argNode = expr.arguments[0];
3862
- if (name === "decodeURIComponent") {
4267
+ if (name === "decodeURIComponent" || name === "decodeURI") {
3863
4268
  const d = optionalCallValue(lowerer, argNode) ?? lowerer.lowerExpr(argNode);
3864
4269
  const s = lowerer.ensureString(d, argNode);
3865
- return { kind: "libCall", fn: "str.decodeUriComponent", args: [s], type: STRING, loc };
4270
+ return { kind: "libCall", fn: name === "decodeURI" ? "str.decodeUri" : "str.decodeUriComponent", args: [s], type: STRING, loc };
3866
4271
  }
3867
4272
  const value = optionalCallValue(lowerer, argNode) ?? lowerer.lowerExpr(argNode);
3868
4273
  const s = lowerer.ensureString(value, argNode);
@@ -4061,6 +4466,9 @@ export function lowerCall(lowerer, expr) {
4061
4466
  let callee = lowerer.lowerExpr(nsMember);
4062
4467
  if (callee.type.kind === "record")
4063
4468
  callee = lowerer.hybridCallUnwrap(callee);
4469
+ const checked = lowerCheckedCallableValue(lowerer, expr, callee, loc);
4470
+ if (checked)
4471
+ return checked;
4064
4472
  if (callee.type.kind !== "func")
4065
4473
  lowerer.badType(expr.expression, lowerer.typeOf(expr.expression));
4066
4474
  const args = completeFuncValueArgs(lowerer, expr, callee.type, loc);
@@ -4114,6 +4522,9 @@ export function lowerCall(lowerer, expr) {
4114
4522
  let callee = lowerer.lowerExpr(nameId);
4115
4523
  if (callee.type.kind === "record")
4116
4524
  callee = lowerer.hybridCallUnwrap(callee);
4525
+ const checked = lowerCheckedCallableValue(lowerer, expr, callee, loc);
4526
+ if (checked)
4527
+ return checked;
4117
4528
  if (callee.type.kind !== "func")
4118
4529
  lowerer.badType(expr.expression, lowerer.typeOf(expr.expression));
4119
4530
  const args = completeFuncValueArgs(lowerer, expr, callee.type, loc);
@@ -4137,7 +4548,8 @@ export function lowerCall(lowerer, expr) {
4137
4548
  lowerer.lowerJsonMethodCall(expr, expr.expression) ??
4138
4549
  // Reflect.apply of a builtin rest-parameter fn (fixtures.js's
4139
4550
  // fixturesPath idiom) — before the stdlib member fence claims it.
4140
- lowerReflectApplyCall(lowerer, expr, expr.expression) ??
4551
+ lowerReflectCall(lowerer, expr, expr.expression) ??
4552
+ lowerBigIntStaticCall(lowerer, expr, expr.expression) ??
4141
4553
  lowerer.lowerNumberStaticCall(expr, expr.expression) ??
4142
4554
  lowerer.lowerDateCall(expr, expr.expression) ??
4143
4555
  lowerer.lowerTextCodecCall(expr, expr.expression) ??
@@ -4193,6 +4605,7 @@ export function lowerCall(lowerer, expr) {
4193
4605
  // TestContext surface (t.test/t.skip/t.diagnostic), t.assert.*.
4194
4606
  lowerer.lowerTestMethodCall(expr, expr.expression) ??
4195
4607
  lowerer.lowerTimeoutMethodCall(expr, expr.expression) ??
4608
+ lowerArrayPrototypeBorrowCall(lowerer, expr, expr.expression) ??
4196
4609
  lowerObjectOwnPrototypeCall(lowerer, expr, expr.expression) ??
4197
4610
  lowerObjectPrototypeCall(lowerer, expr, expr.expression) ??
4198
4611
  lowerStringPrototypeCall(lowerer, expr, expr.expression) ??
@@ -4200,6 +4613,7 @@ export function lowerCall(lowerer, expr) {
4200
4613
  // Typed-array/Buffer receivers and the Buffer statics — before the
4201
4614
  // island path (bytes never cross the boundary).
4202
4615
  lowerer.lowerBytesMethodCall(expr, expr.expression) ??
4616
+ lowerBytesStaticCall(lowerer, expr, expr.expression) ??
4203
4617
  lowerBufferStaticCallWithNarrowedArg(lowerer, expr, expr.expression) ??
4204
4618
  // URL.revokeObjectURL's zero-argument contract (the one-argument
4205
4619
  // form keeps the fence — createObjectURL does too).
@@ -4207,8 +4621,8 @@ export function lowerCall(lowerer, expr) {
4207
4621
  // Readable.from — the stream classes' one static (before the
4208
4622
  // stdlib chokepoint claims the member).
4209
4623
  lowerStreamStaticCall(lowerer, expr, expr.expression) ??
4210
- // Radix-free n.toString() is the STATIC number formatter (identical
4211
- // to `${n}` / String(n)); the explicit-radix form stays island.
4624
+ // Primitive toString calls, including numeric radices, use the
4625
+ // native formatters before the island method path.
4212
4626
  lowerNumberToStringCall(lowerer, expr, expr.expression) ??
4213
4627
  // Union receivers whose every arm has a text — the ngrok
4214
4628
  // `(chunk: Buffer | string) => chunk.toString()` idiom.
@@ -4248,7 +4662,6 @@ export function lowerCall(lowerer, expr) {
4248
4662
  // by the receiver's own element.
4249
4663
  lowerer.lowerFilterNarrowCall(expr, expr.expression) ??
4250
4664
  lowerArrayIsArrayCall(lowerer, expr, expr.expression) ??
4251
- lowerBigIntStaticCall(lowerer, expr, expr.expression) ??
4252
4665
  lowerBigIntMethodCall(lowerer, expr, expr.expression) ??
4253
4666
  lowerSymbolStaticCall(lowerer, expr, expr.expression) ??
4254
4667
  lowerSymbolMethodCall(lowerer, expr, expr.expression) ??
@@ -4267,8 +4680,8 @@ export function lowerCall(lowerer, expr) {
4267
4680
  lowerArrayFromCall(lowerer, expr, expr.expression) ??
4268
4681
  lowerArrayOfCall(lowerer, expr, expr.expression) ??
4269
4682
  lowerer.lowerArrayMethodCall(expr, expr.expression) ??
4270
- // Read-only array methods (slice/map) on TUPLE receivers — the
4271
- // positions snapshot into a fresh array (the for-of stance).
4683
+ // Tuple reads preserve the receiver through argument evaluation;
4684
+ // callbacks read each position when visited.
4272
4685
  lowerTupleReadMethodCall(lowerer, expr, expr.expression) ??
4273
4686
  lowerGenMethodCall(lowerer, expr, expr.expression) ??
4274
4687
  lowerer.lowerMapMethodCall(expr, expr.expression) ??
@@ -4283,6 +4696,25 @@ export function lowerCall(lowerer, expr) {
4283
4696
  lowerObjLitGenericMethodCall(lowerer, expr, expr.expression);
4284
4697
  if (intrinsic)
4285
4698
  return intrinsic;
4699
+ if (isJsSourceFile(expr.getSourceFile())) {
4700
+ const staticField = lowerStaticFieldRead(lowerer, expr.expression);
4701
+ if (staticField?.type.kind === "dyn" && !expr.arguments.some(ts.isSpreadElement)) {
4702
+ return { kind: "dynCall", callee: staticField, receiver: lowerer.lowerExprExpecting(expr.expression.expression, DYN), calleeName: expr.expression.getText(),
4703
+ args: expr.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc: locOf(expr) };
4704
+ }
4705
+ }
4706
+ const accessorTarget = lowerer.fieldTarget(expr.expression);
4707
+ if (accessorTarget?.container === "accessor") {
4708
+ const callee = lowerer.fieldGetExpr(accessorTarget, locOf(expr.expression), expr.expression);
4709
+ if (callee.type.kind === "func") {
4710
+ const args = completeFuncValueArgs(lowerer, expr, callee.type, locOf(expr));
4711
+ return { kind: "callValue", callee, args, type: callee.type.ret, loc: locOf(expr) };
4712
+ }
4713
+ if (callee.type.kind === "dyn" && !expr.arguments.some((arg) => ts.isSpreadElement(arg))) {
4714
+ const args = expr.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN));
4715
+ return { kind: "dynCall", callee, calleeName: expr.expression.getText(), args, type: DYN, loc: locOf(expr) };
4716
+ }
4717
+ }
4286
4718
  // A method call rooted at an initializer-less ambient `declare
4287
4719
  // const/var` whose declared type has no mapping: Node throws the
4288
4720
  // catchable ReferenceError at the ROOT read before the member, the
@@ -4332,6 +4764,9 @@ export function lowerCall(lowerer, expr) {
4332
4764
  // The element spelling of an unsupported native Web method must fence
4333
4765
  // before lowering the callee into a checked-dynamic keyed read.
4334
4766
  if (ts.isElementAccessExpression(expr.expression)) {
4767
+ const symbolMethod = lowerClassSymbolMethodCall(lowerer, expr);
4768
+ if (symbolMethod)
4769
+ return symbolMethod;
4335
4770
  const headersIterator = lowerer.lowerDynamicHeadersIteratorCall(expr, expr.expression);
4336
4771
  if (headersIterator)
4337
4772
  return headersIterator;
@@ -4340,6 +4775,30 @@ export function lowerCall(lowerer, expr) {
4340
4775
  lowerer.fenceStaticHeadersMember(expr.expression, "call");
4341
4776
  lowerer.fenceStaticReadableStreamMember(expr.expression, "call");
4342
4777
  }
4778
+ // Computed native members retain their original receiver and resolve
4779
+ // the function before argument effects, just like dotted calls.
4780
+ if (ts.isElementAccessExpression(expr.expression) && !expr.expression.questionDotToken && !expr.questionDotToken &&
4781
+ !symbolFieldInfo(lowerer, expr.expression)) {
4782
+ const access = expr.expression;
4783
+ const value = tryLowerExpression(lowerer, access.expression);
4784
+ if (value?.type.kind === "dyn" || value?.type.kind === "generator" ||
4785
+ value && ["array", "bytes", "map", "set"].includes(value.type.kind) && lowerer.dynConvertible(value.type) ||
4786
+ value?.type.kind === "string" && !ts.isStringLiteralLike(access.argumentExpression) && lowerer.dynConvertible(value.type) ||
4787
+ value?.type.kind === "object" && !lowerer.classes.get(value.type.className)?.def.runtime) {
4788
+ const local = lowerer.declareHiddenLocal("%computedReceiver", value.type);
4789
+ const reference = { kind: "varRef", localId: local.id, type: value.type, loc };
4790
+ const receiver = lowerer.coerceToExpected(reference, DYN);
4791
+ const raw = lowerer.lowerExpr(access.argumentExpression);
4792
+ const key = raw.type.kind === "string" ? raw : lowerer.coerceInto(access.argumentExpression, raw, DYN);
4793
+ const callee = { kind: "dynKeyGet", value: receiver, key, type: DYN, loc };
4794
+ const spread = expr.arguments.some(ts.isSpreadElement) ? lowerSpreadArgsCall(lowerer, expr, callee, loc) : null;
4795
+ if (spread && spread.kind !== "dynCall")
4796
+ lowerer.unsupported("SC1090", expr, "computed native method spread arguments");
4797
+ const result = spread !== null ? { ...spread, receiver } : { kind: "dynCall", callee, receiver,
4798
+ calleeName: access.getText(), args: expr.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
4799
+ return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id, init: value, loc }], result, type: DYN, loc };
4800
+ }
4801
+ }
4343
4802
  // The ELEMENT spelling of a primitive method call — `x['toString']()`,
4344
4803
  // `s['charAt'](0)`: JS resolves it exactly like the dot form, so the
4345
4804
  // literal-keyed shapes with a static lowering route there before the
@@ -4347,8 +4806,41 @@ export function lowerCall(lowerer, expr) {
4347
4806
  if (ts.isElementAccessExpression(expr.expression) &&
4348
4807
  !expr.expression.questionDotToken &&
4349
4808
  !expr.questionDotToken &&
4350
- ts.isStringLiteralLike(expr.expression.argumentExpression)) {
4351
- const memberName = expr.expression.argumentExpression.text;
4809
+ (ts.isStringLiteralLike(expr.expression.argumentExpression) || ts.isNumericLiteral(expr.expression.argumentExpression))) {
4810
+ const memberName = ts.isNumericLiteral(expr.expression.argumentExpression)
4811
+ ? String(Number(expr.expression.argumentExpression.text))
4812
+ : expr.expression.argumentExpression.text;
4813
+ const receiverType = lowerer.mapTypeOf(lowerer.typeOf(expr.expression.expression));
4814
+ if (receiverType?.kind === "object") {
4815
+ const info = lowerer.classes.get(receiverType.className);
4816
+ const found = info ? lowerer.findMethodOn(info, memberName) : null;
4817
+ if (info && found) {
4818
+ if (found.declarer.builtinError)
4819
+ return errorToStringCall(lowerer, lowerer.lowerExpr(expr.expression.expression));
4820
+ const virtual = lowerer.overrideBelow(info, memberName);
4821
+ if (found.sig.abstract === true && !virtual) {
4822
+ lowerer.unsupported("SC1090", expr, `calls of the abstract method '${memberName}' with no concrete implementation below the receiver's static class`);
4823
+ }
4824
+ if (virtual)
4825
+ lowerer.noteVirtualEdge(info, memberName);
4826
+ else
4827
+ lowerer.noteEdge(`%${found.declarer.def.name}.${memberName}`);
4828
+ const receiver = lowerer.lowerExpr(expr.expression.expression);
4829
+ const args = lowerer.completeArgs(expr.arguments, found.sig.params, locOf(expr), expr);
4830
+ const callArgs = [lowerer.upcastTo(receiver, virtual ? info.def.name : found.declarer.def.name), ...args];
4831
+ const loc = locOf(expr);
4832
+ if (virtual) {
4833
+ return reconcileOverloadReturn(lowerer, expr, {
4834
+ kind: "virtualCall", className: info.def.name, method: memberName,
4835
+ args: callArgs, type: found.sig.ret, loc,
4836
+ });
4837
+ }
4838
+ return reconcileOverloadReturn(lowerer, expr, {
4839
+ kind: "call", callee: `%${found.declarer.def.name}.${memberName}`,
4840
+ args: callArgs, type: found.sig.ret, loc,
4841
+ });
4842
+ }
4843
+ }
4352
4844
  // ts7's getSymbolAtLocation does not resolve element accesses; the
4353
4845
  // member symbol comes from the receiver's (apparent) type instead —
4354
4846
  // same provenance answer as the dot spelling's name symbol.
@@ -4392,6 +4884,11 @@ export function lowerCall(lowerer, expr) {
4392
4884
  : "value";
4393
4885
  return { kind: "dynCall", callee, calleeName, args, type: DYN, loc };
4394
4886
  }
4887
+ if (callee.type.kind === "union" && lowerer.dynConvertible(callee.type) &&
4888
+ lowerer.unions.get(callee.type.unionId)?.arms.some((arm) => arm.kind === "func")) {
4889
+ return { kind: "dynCall", callee: lowerer.coerceToExpected(callee, DYN), calleeName: expr.expression.getText(),
4890
+ args: expr.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
4891
+ }
4395
4892
  if (callee.type.kind !== "func") {
4396
4893
  lowerer.badType(expr.expression, lowerer.typeOf(expr.expression));
4397
4894
  }
@@ -4446,7 +4943,7 @@ export function lowerCall(lowerer, expr) {
4446
4943
  // JS arity exactly (the thunk ignores extras). Result dyn, checked
4447
4944
  // per use like every any-origin value.
4448
4945
  if ((expr.arguments.length > callee.type.params.length || callee.type.rest === true) &&
4449
- isJsSourceFile(expr.getSourceFile()) &&
4946
+ (isJsSourceFile(expr.getSourceFile()) || callee.type.rest === true && callee.type.restAbi === undefined) &&
4450
4947
  !expr.arguments.some((a) => ts.isSpreadElement(a)) &&
4451
4948
  canBoxFuncIntoDyn(callee.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
4452
4949
  const args = expr.arguments.map((a) => lowerer.lowerExprExpecting(a, DYN));
@@ -4457,6 +4954,29 @@ export function lowerCall(lowerer, expr) {
4457
4954
  const args = completeFuncValueArgs(lowerer, expr, callee.type, loc);
4458
4955
  return { kind: "callValue", callee, args, type: callee.type.ret, loc };
4459
4956
  }
4957
+ /** Exported checked and variadic callables use the same runtime-arity ABI
4958
+ * whether the caller spells a bare import or a namespace member. */
4959
+ function lowerCheckedCallableValue(lowerer, call, value, loc) {
4960
+ let callee = value;
4961
+ if (callee.type.kind !== "dyn") {
4962
+ if (callee.type.kind !== "func" ||
4963
+ !(callee.type.rest === true && callee.type.restAbi === undefined ||
4964
+ isJsSourceFile(call.getSourceFile()) && call.arguments.length > callee.type.params.length) ||
4965
+ !lowerer.dynConvertible(callee.type))
4966
+ return null;
4967
+ callee = { kind: "dynFrom", value: callee, type: DYN, loc };
4968
+ }
4969
+ if (call.arguments.some(ts.isSpreadElement)) {
4970
+ const spread = lowerSpreadArgsCall(lowerer, call, callee, loc);
4971
+ if (spread)
4972
+ return spread;
4973
+ lowerer.unsupported("SC1090", call, "spread arguments in calls through 'unknown' values");
4974
+ }
4975
+ return {
4976
+ kind: "dynCall", callee, calleeName: call.expression.getText(),
4977
+ args: call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc,
4978
+ };
4979
+ }
4460
4980
  function lowerRegexMethodCallWithOptionalArg(lowerer, call, access) {
4461
4981
  const lowered = lowerer.lowerRegexMethodCall(call, access);
4462
4982
  if (lowered?.kind !== "regexIntrinsic" || lowered.method !== "test" || call.arguments.length !== 1)
@@ -4478,9 +4998,13 @@ function optionalCallValue(lowerer, node) {
4478
4998
  return lowerer.runtimeOptionalIdentifierValue(node)?.value ?? lowerAbsenceProbe(lowerer, node);
4479
4999
  }
4480
5000
  function lowerBufferStaticCallWithNarrowedArg(lowerer, call, access) {
4481
- const lowered = lowerer.lowerBufferStaticCall(call, access);
5001
+ const result = lowerer.lowerBufferStaticCall(call, access);
5002
+ // The Buffer brand wraps the constructor result. Normalize its source
5003
+ // before restoring that wrapper so narrowed unions never reach bytesNew.
5004
+ const branded = result?.kind === "libCall" && result.fn === "buffer.brand" ? result : null;
5005
+ const lowered = branded ? branded.args[0] : result;
4482
5006
  if (lowered?.kind !== "bytesNew" || !lowered.source || lowered.source.type.kind !== "union")
4483
- return lowered;
5007
+ return result;
4484
5008
  // A callback can store a wider union than the checker sees at this use
4485
5009
  // (including an added undefined arm). Extract the exact arm proven by
4486
5010
  // control-flow narrowing, not merely the union with undefined removed.
@@ -4496,10 +5020,11 @@ function lowerBufferStaticCallWithNarrowedArg(lowerer, call, access) {
4496
5020
  if (!helper) {
4497
5021
  lowerer.unsupported("SC1090", call.arguments[0], "a Buffer constructor argument whose narrowed type is not a stored source arm");
4498
5022
  }
4499
- return {
5023
+ const narrowedValue = {
4500
5024
  ...lowered,
4501
5025
  source: { kind: "call", callee: helper, args: [lowered.source], type: narrowed, loc: lowered.source.loc },
4502
5026
  };
5027
+ return branded ? { ...branded, args: [narrowedValue] } : narrowedValue;
4503
5028
  }
4504
5029
  function lowerOptionalNumberDefault(lowerer, value, dflt, loc) {
4505
5030
  const widened = lowerer.runtimeOptionalWidening(value.type, F64);
@@ -4554,6 +5079,8 @@ function lowerStringMethodCallWithOptionalArgs(lowerer, call, access, receiver,
4554
5079
  ? [1]
4555
5080
  : [];
4556
5081
  for (const index of zeroDefaultArgs) {
5082
+ if (index === undefined)
5083
+ continue;
4557
5084
  const value = args[index];
4558
5085
  if (!value)
4559
5086
  continue;
@@ -4599,6 +5126,12 @@ function lowerNumberConstructorValue(lowerer, argNode, loc) {
4599
5126
  }
4600
5127
  if (arg.type.kind === "string")
4601
5128
  return { kind: "libCall", fn: "num.fromString", args: [arg], type: F64, loc };
5129
+ if (arg.type.kind === "dyn")
5130
+ return { kind: "libCall", fn: "dyn.numberConstructor", args: [arg], type: F64, loc };
5131
+ if (arg.type.kind === "union" && lowerer.dynConvertible(arg.type))
5132
+ return {
5133
+ kind: "libCall", fn: "dyn.numberConstructor", args: [lowerer.coerceToExpected(arg, DYN)], type: F64, loc,
5134
+ };
4602
5135
  const optionalNumber = lowerOptionalStringNumber(lowerer, arg, loc);
4603
5136
  if (optionalNumber)
4604
5137
  return optionalNumber;
@@ -4609,6 +5142,63 @@ function lowerNumberConstructorValue(lowerer, argNode, loc) {
4609
5142
  ? "unions of numbers, booleans, strings, null, and undefined lower — narrow other arms first"
4610
5143
  : undefined);
4611
5144
  }
5145
+ /** A runtime-optional local retains its full tagged storage even after a
5146
+ * checker guard. Dispatch BigInt by the actual value, including nullish
5147
+ * TypeErrors, rather than interpreting that storage as the narrowed arm. */
5148
+ function lowerBigIntConstructorValue(lowerer, arg, loc) {
5149
+ if (arg.type.kind === "dyn")
5150
+ return { kind: "libCall", fn: "dyn.bigintConstructor", args: [arg], type: BIGINT_T, loc };
5151
+ if (arg.type.kind === "bigint")
5152
+ return arg;
5153
+ if (arg.type.kind === "string")
5154
+ return { kind: "libCall", fn: "bigint.parse", args: [arg], type: BIGINT_T, loc };
5155
+ if (arg.type.kind === "f64")
5156
+ return { kind: "libCall", fn: "bigint.fromF64", args: [arg], type: BIGINT_T, loc };
5157
+ if (arg.type.kind === "bool") {
5158
+ return {
5159
+ kind: "ternary", cond: arg,
5160
+ then: { kind: "libCall", fn: "bigint.parse", args: [{ kind: "strLit", value: "1", type: STRING, loc }], type: BIGINT_T, loc },
5161
+ else_: { kind: "libCall", fn: "bigint.parse", args: [{ kind: "strLit", value: "0", type: STRING, loc }], type: BIGINT_T, loc },
5162
+ type: BIGINT_T, loc,
5163
+ };
5164
+ }
5165
+ if (isUnitType(arg.type)) {
5166
+ const name = arg.type.kind === "nullT" ? "null" : "undefined";
5167
+ return defaultAfterUndefined(arg, nodeThrowExpr(1, "", `Cannot convert ${name} to a BigInt`, BIGINT_T, loc));
5168
+ }
5169
+ if (arg.type.kind !== "union")
5170
+ return null;
5171
+ const unionId = arg.type.unionId;
5172
+ const arms = lowerer.unions.get(unionId)?.arms;
5173
+ if (!arms || !arms.every((arm) => arm.kind === "bigint" || arm.kind === "string" || arm.kind === "f64" || arm.kind === "bool" || isUnitType(arm)))
5174
+ return null;
5175
+ const key = `bigint.scalar:${unionId}`;
5176
+ let helper = lowerer.widthHelpers.get(key);
5177
+ if (!helper) {
5178
+ helper = `%bigint.scalar.${lowerer.widthHelpers.size}`;
5179
+ lowerer.widthHelpers.set(key, helper);
5180
+ const value = varRef("value.0", arg.type, loc);
5181
+ const body = [];
5182
+ arms.forEach((arm, tag) => {
5183
+ const narrowed = isUnitType(arm)
5184
+ ? { kind: "unitLit", unit: arm.kind === "nullT" ? "null" : "undefined", type: arm, loc }
5185
+ : { kind: "unionNarrow", unionId, tag, value, type: arm, loc };
5186
+ const converted = lowerBigIntConstructorValue(lowerer, narrowed, loc);
5187
+ if (!converted)
5188
+ throw new InternalCompilerError("BigInt scalar union has an unsupported arm");
5189
+ const ret = { kind: "return", value: converted, loc };
5190
+ body.push(tag === arms.length - 1 ? ret : {
5191
+ kind: "if", cond: { kind: "unionIsTag", unionId, tag, negated: false, value, type: BOOL, loc },
5192
+ then: [ret], else_: null, loc,
5193
+ });
5194
+ });
5195
+ lowerer.liftedFns.push({
5196
+ name: helper, params: [{ localId: "value.0", name: "value", type: arg.type }],
5197
+ returnType: BIGINT_T, locals: [{ id: "value.0", name: "value", type: arg.type, mutable: false }], body, loc,
5198
+ });
5199
+ }
5200
+ return { kind: "call", callee: helper, args: [arg], type: BIGINT_T, loc };
5201
+ }
4612
5202
  function immediatePrimitiveWrapperToString(lowerer, node) {
4613
5203
  const stringValue = stringWrapperToString(lowerer, node);
4614
5204
  if (stringValue)
@@ -4631,24 +5221,6 @@ function immediatePrimitiveWrapperToString(lowerer, node) {
4631
5221
  : args.length ? lowerNumberConstructorValue(lowerer, args[0], loc) : { kind: "numLit", value: 0, type: F64, loc };
4632
5222
  return lowerer.ensureString(primitive, wrapped);
4633
5223
  }
4634
- function plainObjectCoercionReceiver(lowerer, node) {
4635
- const plainLiteral = (literal) => literal.properties.every((prop) => ts.isPropertyAssignment(prop) &&
4636
- (ts.isIdentifier(prop.name) || ts.isStringLiteral(prop.name) || ts.isNumericLiteral(prop.name)) &&
4637
- prop.name.text !== "__proto__");
4638
- let value = node;
4639
- while (ts.isParenthesizedExpression(value))
4640
- value = value.expression;
4641
- if (ts.isObjectLiteralExpression(value))
4642
- return plainLiteral(value);
4643
- if (!ts.isIdentifier(value))
4644
- return false;
4645
- const symbol = lowerer.resolveValueSymbol(value);
4646
- const decl = symbol ? lowerer.checker.valueDeclarationOf(symbol) : undefined;
4647
- if (!symbol || !decl || !ts.isVariableDeclaration(decl) || !decl.initializer ||
4648
- !ts.isObjectLiteralExpression(decl.initializer) || !plainLiteral(decl.initializer))
4649
- return false;
4650
- return bindingNeverReassigned(lowerer, symbol, decl);
4651
- }
4652
5224
  function objectToStringTag(lowerer, type) {
4653
5225
  switch (type.kind) {
4654
5226
  case "undefinedT":
@@ -4669,7 +5241,7 @@ function objectToStringTag(lowerer, type) {
4669
5241
  case "set": return "Set";
4670
5242
  case "promise": return "Promise";
4671
5243
  case "bytes":
4672
- return ({ u8: "Uint8Array", u32: "Uint32Array", i32: "Int32Array", f32: "Float32Array", f64: "Float64Array" })[type.elem];
5244
+ return BYTES_ELEMENT_NAME[type.elem];
4673
5245
  case "object":
4674
5246
  return type.className === "%Error" || lowerer.isSubclassOf(type.className, "%Error") ? "Error" : null;
4675
5247
  default: return null;
@@ -4691,6 +5263,10 @@ function immediateObjectTagReceiver(lowerer, node) {
4691
5263
  lowerer.isStdlibSymbol(lowerer.resolveValueSymbol(value.expression) ?? undefined)) {
4692
5264
  const name = value.expression.text;
4693
5265
  const args = value.arguments ?? [];
5266
+ // JavaScript dates use checked native handles, so their IR type alone
5267
+ // cannot recover the tag through an immediate Object(...) wrapper.
5268
+ if (name === "Date")
5269
+ return { tag: "Date", effect: lowerer.lowerExpr(value) };
4694
5270
  if (args.length <= 1 && !args.some(ts.isSpreadElement)) {
4695
5271
  if (name === "String") {
4696
5272
  const effect = stringWrapperToString(lowerer, value);
@@ -4738,6 +5314,36 @@ function immediateObjectTagReceiver(lowerer, node) {
4738
5314
  }
4739
5315
  return null;
4740
5316
  }
5317
+ const ARRAY_BORROW_METHODS = new Set([
5318
+ "at", "every", "filter", "find", "findIndex", "findLast", "findLastIndex", "forEach", "includes",
5319
+ "indexOf", "lastIndexOf", "map", "reduce", "reduceRight", "slice", "some",
5320
+ ]);
5321
+ function lowerArrayPrototypeBorrowCall(lowerer, call, access) {
5322
+ if (lowerer.dynamic || !isJsSourceFile(call.getSourceFile()) || call.questionDotToken ||
5323
+ access.questionDotToken || access.name.text !== "call" ||
5324
+ !ts.isPropertyAccessExpression(access.expression) ||
5325
+ call.arguments.some(ts.isSpreadElement))
5326
+ return null;
5327
+ const method = access.expression;
5328
+ if (method.questionDotToken || !ARRAY_BORROW_METHODS.has(method.name.text) ||
5329
+ !ts.isPropertyAccessExpression(method.expression) ||
5330
+ method.expression.questionDotToken || method.expression.name.text !== "prototype" ||
5331
+ !lowerer.isStdlibGlobal(method.expression.expression, "Array") ||
5332
+ !lowerer.isStdlibMember(method))
5333
+ return null;
5334
+ const loc = locOf(call);
5335
+ const receiver = call.arguments[0]
5336
+ ? lowerer.lowerExprExpecting(call.arguments[0], DYN)
5337
+ : { kind: "dynFrom", value: { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc }, type: DYN, loc };
5338
+ const args = call.arguments.slice(1).map((arg) => lowerer.lowerExprExpecting(arg, DYN));
5339
+ return {
5340
+ kind: "libCall", fn: "dyn.arrayProtoCall", args: [
5341
+ receiver,
5342
+ { kind: "strLit", value: method.name.text, type: STRING, loc },
5343
+ { kind: "dynArrLit", elems: args, type: DYN, loc },
5344
+ ], type: DYN, loc,
5345
+ };
5346
+ }
4741
5347
  function lowerObjectOwnPrototypeCall(lowerer, call, access) {
4742
5348
  if (lowerer.dynamic || access.name.text !== "call" || !ts.isPropertyAccessExpression(access.expression))
4743
5349
  return null;
@@ -4756,10 +5362,31 @@ function lowerObjectOwnMethodCall(lowerer, call, access) {
4756
5362
  const method = access.name.text;
4757
5363
  if (lowerer.dynamic || call.questionDotToken || access.questionDotToken ||
4758
5364
  (method !== "hasOwnProperty" && method !== "propertyIsEnumerable") ||
4759
- !lowerer.isStdlibMember(access) || call.arguments.some(ts.isSpreadElement))
5365
+ call.arguments.some(ts.isSpreadElement))
4760
5366
  return null;
5367
+ if (!lowerer.isStdlibMember(access)) {
5368
+ const receiver = tryLowerExpression(lowerer, access.expression);
5369
+ if (receiver?.type.kind !== "dyn")
5370
+ return null;
5371
+ }
4761
5372
  return lowerObjectOwnCall(lowerer, call, access.expression, call.arguments[0], call.arguments.slice(1), method);
4762
5373
  }
5374
+ /** ToPropertyKey for the scalar keys represented by native own-key
5375
+ * probes. A lowered array-loop key may carry an undefined arm even when
5376
+ * its checker type is string; that arm spells "undefined" at runtime. */
5377
+ function ownPropertyKey(lowerer, key) {
5378
+ if (key.type.kind === "string")
5379
+ return key;
5380
+ if (key.type.kind === "bigint") {
5381
+ return { kind: "libCall", fn: "bigint.toString", args: [key, numLit(10, key.loc)], type: STRING, loc: key.loc };
5382
+ }
5383
+ const scalar = (type) => type.kind === "string" || type.kind === "f64" || type.kind === "bool" || isUnitType(type);
5384
+ if (key.type.kind === "f64" || key.type.kind === "bool" || key.type.kind === "dyn" ||
5385
+ (key.type.kind === "union" && lowerer.unions.get(key.type.unionId)?.arms.every(scalar))) {
5386
+ return { kind: "toString", operand: key, type: STRING, loc: key.loc };
5387
+ }
5388
+ return null;
5389
+ }
4763
5390
  function lowerObjectOwnCall(lowerer, call, receiverNode, keyNode, extraNodes, method) {
4764
5391
  const enumerable = method === "propertyIsEnumerable";
4765
5392
  const loc = locOf(call);
@@ -4792,14 +5419,19 @@ function lowerObjectOwnCall(lowerer, call, receiverNode, keyNode, extraNodes, me
4792
5419
  stmts.push({ kind: "exprStmt", expr: effect, loc: locOf(extra) });
4793
5420
  }
4794
5421
  let key = keyRef;
5422
+ if (lowerer.dynConvertible(receiverRef.type) && keyRef && (receiverRef.type.kind === "object" || keyRef.type.kind === "symbol" || keyRef.type.kind === "dyn" ||
5423
+ keyRef.type.kind === "union" && lowerer.dynConvertible(keyRef.type))) {
5424
+ const result = { kind: "libCall", fn: enumerable ? "dyn.propertyIsEnumerableComputed" : "dyn.hasOwnComputed", args: [lowerer.coerceToExpected(receiverRef, DYN), lowerer.coerceToExpected(keyRef, DYN)], type: BOOL, loc };
5425
+ return { kind: "seqExpr", stmts, result, type: BOOL, loc };
5426
+ }
4795
5427
  if (!keyNode || rawKey?.type.kind === "undefinedT" || rawKey?.type.kind === "void") {
4796
5428
  key = { kind: "strLit", value: "undefined", type: STRING, loc };
4797
5429
  }
4798
5430
  else if (rawKey?.type.kind === "nullT") {
4799
5431
  key = { kind: "strLit", value: "null", type: STRING, loc };
4800
5432
  }
4801
- else if (key && (key.type.kind === "f64" || key.type.kind === "bool" || key.type.kind === "bigint")) {
4802
- key = { kind: "toString", operand: key, type: STRING, loc };
5433
+ else if (key) {
5434
+ key = ownPropertyKey(lowerer, key);
4803
5435
  }
4804
5436
  if (!key || key.type.kind !== "string") {
4805
5437
  lowerer.noLowering("Object.prototype." + method + " with this property key", keyNode ?? call);
@@ -4811,13 +5443,13 @@ function lowerObjectOwnCall(lowerer, call, receiverNode, keyNode, extraNodes, me
4811
5443
  }
4812
5444
  else if (type.kind === "record") {
4813
5445
  const shape = lowerer.shapes.get(type.shapeId);
4814
- if (!shape || shape.tuple || shape.indexValue || shapeHasAccessorSlots(shape)) {
5446
+ if (!shape || shape.tuple || shapeHasAccessorSlots(shape)) {
4815
5447
  lowerer.noLowering("Object.prototype." + method + " over this record shape", receiverNode ?? call);
4816
5448
  }
4817
5449
  result = { kind: "call", callee: recordHasOwnHelper(lowerer, type.shapeId, loc), args: [receiverRef, key], type: BOOL, loc };
4818
5450
  }
4819
- else if (type.kind === "dyn" && !enumerable) {
4820
- result = { kind: "libCall", fn: "dyn.hasOwn", args: [receiverRef, key], type: BOOL, loc };
5451
+ else if (type.kind === "dyn") {
5452
+ result = { kind: "libCall", fn: enumerable ? "dyn.propertyIsEnumerable" : "dyn.hasOwn", args: [receiverRef, key], type: BOOL, loc };
4821
5453
  }
4822
5454
  else if (type.kind === "string" || type.kind === "array") {
4823
5455
  const needleLocal = lowerer.declareHiddenLocal("%ownIndex", F64);
@@ -4886,6 +5518,52 @@ function lowerObjectPrototypeCall(lowerer, call, access) {
4886
5518
  : { kind: "strLit", value: "[object " + tag + "]", type: STRING, loc };
4887
5519
  return { kind: "seqExpr", stmts, result, type: STRING, loc };
4888
5520
  }
5521
+ /** Function.call evaluates all arguments before RequireObjectCoercible and
5522
+ * ToString. Stabilize them before reusing the ordinary string method lowering,
5523
+ * so a boxed nullish receiver or a coercion hook cannot reorder effects. */
5524
+ function lowerDynamicStringPrototypeCall(lowerer, call, methodAccess, receiver, method) {
5525
+ const loc = locOf(call);
5526
+ const receiverLocal = lowerer.declareHiddenLocal("%stringCallReceiver", receiver.type);
5527
+ const stmts = [{ kind: "varDecl", localId: receiverLocal.id, init: receiver, loc }];
5528
+ const receiverRef = varRef(receiverLocal.id, receiver.type, loc);
5529
+ const converted = {
5530
+ kind: "ternary",
5531
+ cond: { kind: "dynTest", test: "nullish", value: receiverRef, type: BOOL, loc },
5532
+ then: nodeThrowExpr(1, "", `String.prototype.${method} called on null or undefined`, STRING, loc),
5533
+ else_: { kind: "libCall", fn: "dyn.toStringCoerce", args: [receiverRef], type: STRING, loc },
5534
+ type: STRING, loc,
5535
+ };
5536
+ const overrides = [];
5537
+ try {
5538
+ for (const node of call.arguments.slice(1)) {
5539
+ const undefinedValue = lowerStaticallyUndefinedArgument(lowerer, node);
5540
+ const value = undefinedValue ?? lowerer.lowerExpr(node);
5541
+ let ref;
5542
+ if (undefinedValue || isUnitType(value.type) || value.type.kind === "void") {
5543
+ stmts.push({ kind: "exprStmt", expr: value, loc: value.loc });
5544
+ const nullUnit = !undefinedValue && value.type.kind === "nullT";
5545
+ ref = { kind: "unitLit", unit: nullUnit ? "null" : "undefined", type: nullUnit ? value.type : UNDEFINED_T, loc: value.loc };
5546
+ }
5547
+ else {
5548
+ const local = lowerer.declareHiddenLocal("%stringCallArg", value.type);
5549
+ stmts.push({ kind: "varDecl", localId: local.id, init: value, loc: value.loc });
5550
+ ref = varRef(local.id, value.type, value.loc);
5551
+ }
5552
+ overrides.push({ node, previous: lowerer.chainRecvByNode.get(node) });
5553
+ lowerer.chainRecvByNode.set(node, ref);
5554
+ }
5555
+ const result = lowerStringMethodCallWithOptionalArgs(lowerer, call, methodAccess, () => converted, call.arguments.slice(1));
5556
+ return result ? { kind: "seqExpr", stmts, result, type: result.type, loc } : null;
5557
+ }
5558
+ finally {
5559
+ for (const override of overrides) {
5560
+ if (override.previous)
5561
+ lowerer.chainRecvByNode.set(override.node, override.previous);
5562
+ else
5563
+ lowerer.chainRecvByNode.delete(override.node);
5564
+ }
5565
+ }
5566
+ }
4889
5567
  function lowerStringPrototypeCall(lowerer, call, access) {
4890
5568
  if (access.name.text !== "call" || !ts.isPropertyAccessExpression(access.expression))
4891
5569
  return null;
@@ -4928,6 +5606,9 @@ function lowerStringPrototypeCall(lowerer, call, access) {
4928
5606
  loc,
4929
5607
  };
4930
5608
  }
5609
+ if (receiverType.kind === "dyn") {
5610
+ return lowerDynamicStringPrototypeCall(lowerer, call, methodAccess, receiverValue, method);
5611
+ }
4931
5612
  const padding = entry?.method === "padStart" || entry?.method === "padEnd";
4932
5613
  const scalar = receiverType.kind === "string" || receiverType.kind === "f64" ||
4933
5614
  receiverType.kind === "bool" || receiverType.kind === "bigint" ||
@@ -4936,10 +5617,11 @@ function lowerStringPrototypeCall(lowerer, call, access) {
4936
5617
  // padding uses a helper that delays conversion until every argument is ready.
4937
5618
  const objectWithoutMethodArgs = entry?.maxArgs === 0 && call.arguments.length === 1 &&
4938
5619
  (receiverType.kind === "record" || receiverType.kind === "array" || receiverType.kind === "object");
4939
- const dynObjectWithoutMethodArgs = entry?.maxArgs === 0 && call.arguments.length === 1 &&
4940
- receiverType.kind === "dyn" && plainObjectCoercionReceiver(lowerer, receiverNode);
4941
- if (!scalar && !objectWithoutMethodArgs && !dynObjectWithoutMethodArgs && !(padding && receiverType.kind === "dyn")) {
4942
- return lowerer.noLowering(`String.prototype.${methodAccess.name.text}.call with ${lowerer.fmt(receiverType)} receivers`, call);
5620
+ if (padding && !scalar && lowerer.dynConvertible(receiverType)) {
5621
+ return lowerStringPaddingCall(lowerer, call, entry.method, lowerer.coerceToExpected(receiverValue, DYN), receiverNode, call.arguments.slice(1));
5622
+ }
5623
+ if (!scalar && !objectWithoutMethodArgs) {
5624
+ lowerer.noLowering(`String.prototype.${methodAccess.name.text}.call with ${lowerer.fmt(receiverType)} receivers`, call);
4943
5625
  }
4944
5626
  if (indexMethod)
4945
5627
  return lowerStringIndexCall(lowerer, call, indexMethod, receiverValue, receiverNode, call.arguments.slice(1));
@@ -4951,9 +5633,7 @@ function lowerStringPrototypeCall(lowerer, call, access) {
4951
5633
  if (entry.method === "split") {
4952
5634
  return lowerStringSplitCall(lowerer, call, receiverValue, receiverNode, call.arguments.slice(1));
4953
5635
  }
4954
- const receiver = dynObjectWithoutMethodArgs
4955
- ? { kind: "libCall", fn: "dyn.toStringCoerce", args: [receiverValue], type: STRING, loc }
4956
- : lowerer.ensureString(receiverValue, receiverNode);
5636
+ const receiver = lowerer.ensureString(receiverValue, receiverNode);
4957
5637
  return lowerStringMethodCallWithOptionalArgs(lowerer, call, methodAccess, () => receiver, call.arguments.slice(1));
4958
5638
  }
4959
5639
  function lowerScalarUnionNumber(lowerer, arg, node, loc) {
@@ -5127,13 +5807,18 @@ function spreadNeedsRuntimeArity(lowerer, shapes, argNodes) {
5127
5807
  position += tuple.fields.length;
5128
5808
  continue;
5129
5809
  }
5130
- if (restAt < 0 || position < restAt || shapes[restAt].mode !== "rest")
5131
- return true;
5810
+ if (restAt < 0 || position < restAt || shapes[restAt].mode !== "rest") {
5811
+ return !canCompleteRuntimeSpread(lowerer, shapes);
5812
+ }
5132
5813
  }
5133
5814
  position++;
5134
5815
  }
5135
5816
  return false;
5136
5817
  }
5818
+ function canCompleteRuntimeSpread(lowerer, shapes) {
5819
+ return shapes.length > 0 && shapes.every((shape) => shape.mode !== "islandRest" && shape.callDefault === undefined &&
5820
+ canDynCheckTo(shape.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id)));
5821
+ }
5137
5822
  /** METHOD calls on dyn receivers (`pkg.name.replace(...)`, `rawName.split`,
5138
5823
  * `ws.packages.filter(...)` — JSON.parse-derived values): validate the
5139
5824
  * receiver's dyn kind, extract, and ride the STATIC method machinery — the
@@ -5171,18 +5856,70 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
5171
5856
  // tsc types the return by the evolved shape, the binding lowered
5172
5857
  // dyn): probe the lowering and claim exactly the dyn results.
5173
5858
  const probed = tryLowerExpression(lowerer, access.expression);
5859
+ if (probed?.type.kind === "func" && stdlibGlobalNameOf(lowerer, access.expression) === null &&
5860
+ !["call", "apply", "bind", "toString", "valueOf", "constructor"].includes(access.name.text) &&
5861
+ canBoxFuncIntoDyn(probed.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
5862
+ const loc = locOf(call);
5863
+ const fnName = jsFuncNameOf(access.expression);
5864
+ const boxed = { kind: "dynFrom", value: probed, type: DYN, loc, ...(fnName !== null ? { fnName } : {}) };
5865
+ const local = lowerer.declareHiddenLocal("%callableReceiver", DYN);
5866
+ const receiver = { kind: "varRef", localId: local.id, type: DYN, loc };
5867
+ const member = {
5868
+ kind: "dynKeyGet", value: receiver,
5869
+ key: { kind: "strLit", value: access.name.text, type: STRING, loc }, type: DYN, loc,
5870
+ };
5871
+ if (call.arguments.some(ts.isSpreadElement)) {
5872
+ lowerer.unsupported("SC1090", call, "spread arguments in callable property calls");
5873
+ }
5874
+ return {
5875
+ kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id, init: boxed, loc }],
5876
+ result: { kind: "dynCall", callee: member, receiver, calleeName: access.getText(),
5877
+ args: call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc }, type: DYN, loc,
5878
+ };
5879
+ }
5880
+ if (probed?.type.kind === "classval") {
5881
+ const info = lowerer.classes.get(probed.type.className);
5882
+ if (info && (info.callableBase || hasRuntimeStatics(info)))
5883
+ return lowerStaticMethodCall(lowerer, call, access);
5884
+ }
5174
5885
  if (probed?.type.kind !== "dyn")
5175
5886
  return null;
5176
5887
  recv = probed;
5177
5888
  }
5889
+ // A factory may return a constructor more precise than its inferred
5890
+ // checker result. Runtime static members live on that constructor.
5891
+ if (recv.type.kind === "classval") {
5892
+ const info = lowerer.classes.get(recv.type.className);
5893
+ if (info && (info.callableBase || hasRuntimeStatics(info)))
5894
+ return lowerStaticMethodCall(lowerer, call, access);
5895
+ }
5178
5896
  // A checker-`any` receiver that already lowered to a real STRING (the
5179
5897
  // chained form — `cfg.host.trim().toLowerCase()`, where the first step
5180
5898
  // extracted): no validation needed, ride the string tables directly.
5899
+ if (recv.type.kind === "union" && lowerer.stripUndefinedArm(recv.type).kind === "string") {
5900
+ const present = lowerer.runtimeOptionalPropertyReceiver(access.expression, recv, STRING, access.name.text);
5901
+ if (present)
5902
+ recv = present;
5903
+ }
5181
5904
  if (recv.type.kind === "string") {
5182
5905
  return lowerRegexMethodCall(lowerer, call, access, () => recv) ?? lowerStringMethodCall(lowerer, call, access, () => recv);
5183
5906
  }
5184
5907
  if (recv.type.kind !== "dyn")
5185
5908
  return null;
5909
+ if (lowerer.mapTypeOf(recvTs)?.kind === "classval") {
5910
+ return lowerStaticMethodCall(lowerer, call, access);
5911
+ }
5912
+ const ownCallable = !checkerUntyped && (() => {
5913
+ const prop = lowerer.checker.getPropertyOfType(recvTs, access.name.text);
5914
+ if (prop === undefined)
5915
+ return false;
5916
+ // getPropertyOfType includes inherited Object.prototype members.
5917
+ // Those are not stored members of a checked-dynamic object, so
5918
+ // dynKeyGet cannot stand in for JavaScript's prototype lookup. Only
5919
+ // an authored declaration can justify the own-member path.
5920
+ const authored = lowerer.checker.declarationsOf(prop).some((decl) => !lowerer.isStdlibFile(decl.getSourceFile()));
5921
+ return authored && lowerer.checker.getCallSignatures(lowerer.checker.getTypeOfSymbol(prop)).length > 0;
5922
+ })();
5186
5923
  // Typed-destination filter first (validated extraction into a real
5187
5924
  // T[]); an untyped destination falls through to the runtime dispatch
5188
5925
  // below (the survivors stay dyn values).
@@ -5198,34 +5935,21 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
5198
5935
  // these, "the receiver is a string, or the call throws V8's TypeError"
5199
5936
  // IS Node's semantics for every possible dyn value. Shared names would
5200
5937
  // need a receiver-kind dispatch — they keep the fence.
5201
- if (DYN_STRING_ONLY_METHODS.has(access.name.text)) {
5938
+ if (DYN_STRING_ONLY_METHODS.has(access.name.text) && !ownCallable) {
5202
5939
  const checked = () => dynStringReceiver(lowerer, recv, access);
5203
5940
  return lowerRegexMethodCall(lowerer, call, access, checked) ?? lowerStringMethodCall(lowerer, call, access, checked);
5204
5941
  }
5205
- // toString() is a shared prototype name with its OWN receiver-kind
5206
- // dispatched runtime lowering (dyn.toString: Buffer-flavored bytes
5207
- // decode per the encoding — a stream chunk's common consumption —
5208
- // and strings/numbers/booleans/arrays/objects answer JS-exactly).
5209
- // The optional argument is a literal encoding (meaningful for bytes;
5210
- // JS ignores extra toString arguments on the other kinds, and so
5211
- // does the runtime dispatch).
5942
+ // The argument is a radix for bigint and an encoding for Buffer.
5943
+ // Preserve its runtime value so receiver dispatch can choose correctly.
5212
5944
  if (access.name.text === "toString" && call.arguments.length <= 1) {
5213
- const enc = call.arguments[0]
5214
- ? bufEncoding(lowerer, "toString", call.arguments[0])
5215
- : "utf8";
5216
- // The source spelling rides along for the ONE receiver whose
5217
- // prototype lacks toString: a null-prototype dictionary throws
5218
- // Node's "<spelling> is not a function" at runtime.
5945
+ const argument = call.arguments[0];
5219
5946
  return {
5220
- kind: "libCall",
5221
- fn: "dyn.toString",
5222
- args: [
5947
+ kind: "libCall", fn: "dyn.toString", args: [
5223
5948
  recv,
5224
- { kind: "strLit", value: enc, type: STRING, loc: locOf(call) },
5949
+ argument ? lowerer.lowerExprExpecting(argument, DYN)
5950
+ : dynUndefinedExpr(locOf(call)),
5225
5951
  { kind: "strLit", value: access.getText(), type: STRING, loc: locOf(call) },
5226
- ],
5227
- type: STRING,
5228
- loc: locOf(call),
5952
+ ], type: STRING, loc: locOf(call),
5229
5953
  };
5230
5954
  }
5231
5955
  // SHARED prototype names with a runtime dispatch (scr_dyn_invoke):
@@ -5237,7 +5961,13 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
5237
5961
  // unimplemented methods throw a LOUD not-supported Error; names the
5238
5962
  // kind's prototype lacks throw Node's "x.y is not a function"; OBJ
5239
5963
  // receivers call the own member.
5240
- const dispatched = lowerDynDispatchMethodCall(lowerer, call, access, recv, arrayReceiver);
5964
+ // A stored callback must be read before argument effects, and called
5965
+ // with the original receiver rather than a materialized property view.
5966
+ const callbackProperty = (() => {
5967
+ const prop = lowerer.checker.getPropertyOfType(recvTs, access.name.text);
5968
+ return prop !== undefined && lowerer.checker.declarationsOf(prop).some((decl) => ts.isPropertyDeclaration(decl) || ts.isPropertySignature(decl));
5969
+ })();
5970
+ const dispatched = callbackProperty ? null : lowerDynDispatchMethodCall(lowerer, call, access, recv, arrayReceiver);
5241
5971
  if (dispatched)
5242
5972
  return dispatched;
5243
5973
  // Names NO dyn-representable prototype declares: the member can only
@@ -5256,17 +5986,6 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
5256
5986
  // its name overlaps a primitive prototype (`colors.bold(...)`): the
5257
5987
  // source value was compiled from that object shape, while genuinely
5258
5988
  // untyped/any receivers retain the runtime-kind ambiguity and fence.
5259
- const ownCallable = !checkerUntyped && (() => {
5260
- const prop = lowerer.checker.getPropertyOfType(recvTs, access.name.text);
5261
- if (prop === undefined)
5262
- return false;
5263
- // getPropertyOfType includes inherited Object.prototype members.
5264
- // Those are not stored members of a checked-dynamic object, so
5265
- // dynKeyGet cannot stand in for JavaScript's prototype lookup. Only
5266
- // an authored declaration can justify the own-member path.
5267
- const authored = lowerer.checker.declarationsOf(prop).some((decl) => !lowerer.isStdlibFile(decl.getSourceFile()));
5268
- return authored && lowerer.checker.getCallSignatures(lowerer.checker.getTypeOfSymbol(prop)).length > 0;
5269
- })();
5270
5989
  if (DYN_PROTO_METHOD_NAMES.has(access.name.text) && !ownCallable)
5271
5990
  return null;
5272
5991
  // Optional forms (`obj.cb?.()`, `obj?.cb()`) belong to the chain
@@ -5274,18 +5993,28 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
5274
5993
  if (call.questionDotToken || access.questionDotToken)
5275
5994
  return null;
5276
5995
  const loc = locOf(call);
5277
- if (call.arguments.some((a) => ts.isSpreadElement(a))) {
5278
- lowerer.unsupported("SC1090", call, "spread arguments in calls through 'unknown' values");
5279
- }
5996
+ const receiverLocal = lowerer.declareHiddenLocal("%dynCallReceiver", DYN);
5997
+ const receiver = { kind: "varRef", localId: receiverLocal.id, type: DYN, loc };
5280
5998
  const member = {
5281
5999
  kind: "dynKeyGet",
5282
6000
  key: { kind: "strLit", value: access.name.text, type: STRING, loc: locOf(access) },
5283
- value: recv,
6001
+ value: receiver,
5284
6002
  type: DYN,
5285
6003
  loc: locOf(access),
5286
6004
  };
6005
+ if (call.arguments.some(ts.isSpreadElement)) {
6006
+ const spread = lowerSpreadArgsCall(lowerer, call, member, loc);
6007
+ if (spread?.kind === "dynCall")
6008
+ return { kind: "seqExpr",
6009
+ stmts: [{ kind: "varDecl", localId: receiverLocal.id, init: recv, loc }],
6010
+ result: { ...spread, receiver }, type: DYN, loc };
6011
+ lowerer.unsupported("SC1090", call, "spread arguments in calls through 'unknown' values");
6012
+ }
5287
6013
  const args = call.arguments.map((a) => lowerer.lowerExprExpecting(a, DYN));
5288
- return { kind: "dynCall", callee: member, calleeName: access.getText(), args, type: DYN, loc };
6014
+ return {
6015
+ kind: "seqExpr", stmts: [{ kind: "varDecl", localId: receiverLocal.id, init: recv, loc }],
6016
+ result: { kind: "dynCall", callee: member, receiver, calleeName: access.getText(), args, type: DYN, loc }, type: DYN, loc,
6017
+ };
5289
6018
  }
5290
6019
  /** Prototype method names of the checked-dynamic tree-representable kinds (String, Array,
5291
6020
  * Object, Function, Number prototypes): a dyn receiver call on one of
@@ -5312,7 +6041,8 @@ const DYN_PROTO_METHOD_NAMES = new Set([
5312
6041
  * is-not-a-function where the kind's prototype lacks the name, and
5313
6042
  * fences LOUDLY on real-but-unimplemented pairs. */
5314
6043
  const DYN_DISPATCH_METHODS = new Set([
5315
- "apply", "call",
6044
+ "segment", "containing", "resolvedOptions", "test", "exec",
6045
+ "apply", "bind", "call",
5316
6046
  "push", "pop", "shift", "unshift", "slice", "at",
5317
6047
  "indexOf", "lastIndexOf", "includes", "join", "concat", "reverse", "sort",
5318
6048
  "forEach", "map", "filter", "some", "every", "find", "findIndex",
@@ -5330,7 +6060,7 @@ const DYN_DISPATCH_METHODS = new Set([
5330
6060
  "setEncoding", "setDefaultEncoding", "setTimeout", "read", "isPaused",
5331
6061
  "writeHead", "setHeader", "getHeader", "hasHeader", "removeHeader",
5332
6062
  "getHeaders", "getHeaderNames", "appendHeader", "flushHeaders",
5333
- "append", "delete", "get", "getSetCookie", "has", "set",
6063
+ "add", "append", "delete", "get", "getSetCookie", "has", "set", "clear", "keys", "values", "entries", "next",
5334
6064
  "writeContinue", "writeEarlyHints", "cork", "uncork", "addTrailers",
5335
6065
  "ref", "unref", "address", "setNoDelay", "setKeepAlive", "connect",
5336
6066
  "resetAndDestroy", "destroySoon",
@@ -5351,7 +6081,7 @@ const DYN_DISPATCH_METHODS = new Set([
5351
6081
  "dispatchEvent",
5352
6082
  "preventDefault", "stopPropagation", "stopImmediatePropagation",
5353
6083
  "composedPath",
5354
- "json", "text", "bytes",
6084
+ "json", "text", "bytes", "arrayBuffer",
5355
6085
  // Promise.prototype (SCR_DYN_PROMISE receivers): the reaction trio
5356
6086
  // rides the fiber machinery (scr_dyn_promise_then); on every other dyn
5357
6087
  // kind then/catch/finally answer the stored-member path (OBJ own
@@ -5368,9 +6098,20 @@ const DYN_DISPATCH_METHODS = new Set([
5368
6098
  ]);
5369
6099
  export function lowerDynDispatchMethodCall(lowerer, call, access, recv, arrayReceiver) {
5370
6100
  const method = access.name.text;
5371
- if (!DYN_DISPATCH_METHODS.has(method) || call.questionDotToken || access.questionDotToken)
6101
+ if ((!DYN_DISPATCH_METHODS.has(method) && !isJsSourceFile(call.getSourceFile())) || lowerer.chainBlocked(call, access))
5372
6102
  return null;
5373
6103
  if (call.arguments.some((arg) => ts.isSpreadElement(arg))) {
6104
+ const loc = locOf(call);
6105
+ const local = lowerer.declareHiddenLocal("%spreadReceiver", DYN);
6106
+ const receiver = varRef(local.id, DYN, loc);
6107
+ const callee = { kind: "dynKeyGet", value: receiver,
6108
+ key: { kind: "strLit", value: method, type: STRING, loc }, type: DYN, loc };
6109
+ const spread = lowerSpreadArgsCall(lowerer, call, callee, loc);
6110
+ if (spread?.kind === "dynCall")
6111
+ return { kind: "seqExpr",
6112
+ stmts: [{ kind: "varDecl", localId: local.id, init: recv, loc },
6113
+ { kind: "exprStmt", expr: { kind: "libCall", fn: "dyn.arrayPrototype", args: [], type: DYN, loc }, loc }],
6114
+ result: { ...spread, receiver }, type: DYN, loc };
5374
6115
  lowerer.unsupported("SC1090", call, "spread arguments in calls through 'unknown' values");
5375
6116
  }
5376
6117
  const predicate = method === "filter" && call.arguments[0]
@@ -5444,7 +6185,12 @@ export function lowerDynDispatchMethodCall(lowerer, call, access, recv, arrayRec
5444
6185
  }
5445
6186
  }
5446
6187
  }
5447
- const args = call.arguments.map((arg, i) => i === 0 && predicate ? lowerer.coerceInto(arg, predicate, DYN) : lowerer.lowerExprExpecting(arg, DYN));
6188
+ const args = call.arguments.map((arg, i) => {
6189
+ if (i === 0 && predicate)
6190
+ return lowerer.coerceInto(arg, predicate, DYN);
6191
+ const undefinedArg = lowerStaticallyUndefinedArgument(lowerer, arg);
6192
+ return undefinedArg ? defaultAfterUndefined(undefinedArg, dynUndefinedExpr(locOf(arg))) : lowerer.lowerExprExpecting(arg, DYN);
6193
+ });
5448
6194
  return {
5449
6195
  kind: "dynInvoke",
5450
6196
  recv,
@@ -5494,7 +6240,8 @@ function lowerArrayIsArrayCall(lowerer, call, access) {
5494
6240
  // over side-effect-free reads (the operand re-evaluates/drops, the
5495
6241
  // `in`-operator fold discipline). dyn/caught/jsval arms have no
5496
6242
  // static tag answer and keep the narrow-first fence.
5497
- const def = lowerer.unions.get(arg.type.unionId);
6243
+ const unionId = arg.type.unionId;
6244
+ const def = lowerer.unions.get(unionId);
5498
6245
  const opaque = !def || def.arms.some((a) => a.kind === "dyn" || a.kind === "caught" || a.kind === "jsval");
5499
6246
  const arrayTags = lowerer.arrayValueTags(arg.type.unionId);
5500
6247
  const freeRead = arg.kind === "varRef" || arg.kind === "recordGet" || arg.kind === "fieldGet";
@@ -5506,7 +6253,7 @@ function lowerArrayIsArrayCall(lowerer, call, access) {
5506
6253
  }
5507
6254
  if (!opaque && freeRead && arrayTags.length > 1) {
5508
6255
  return arrayTags
5509
- .map((tag) => ({ kind: "unionIsTag", unionId: arg.type.unionId, tag, negated: false, value: arg, type: BOOL, loc }))
6256
+ .map((tag) => ({ kind: "unionIsTag", unionId: unionId, tag, negated: false, value: arg, type: BOOL, loc }))
5510
6257
  .reduce((left, right) => ({ kind: "logical", op: "||", left, right, type: BOOL, loc }));
5511
6258
  }
5512
6259
  lowerer.unsupported("SC1090", argNode, `Array.isArray on '${lowerer.fmt(arg.type)}' values (narrow first: check a discriminant field, or compare with '!== undefined'/'!== null' for unit arms)`);
@@ -5569,13 +6316,13 @@ function lowerCaughtPredicateCall(lowerer, call, caughtLocal) {
5569
6316
  * and String(n) lower to (Number::toString with radix 10 IS that
5570
6317
  * conversion, per spec) — booleans the "true"/"false" texts, and strings
5571
6318
  * the identity read (String.prototype.toString returns `this`). The
5572
- * explicit-radix number form keeps its island lowering (ISLAND_SURFACE);
6319
+ * explicit-radix number form uses the native radix formatter;
5573
6320
  * null for other receivers, argument shapes, or non-lib members (a
5574
6321
  * user's own `.toString` takes the ordinary paths). */
5575
6322
  function lowerNumberToStringCall(lowerer, call, access) {
5576
6323
  if (lowerer.chainBlocked(call, access))
5577
6324
  return null;
5578
- if (access.name.text !== "toString" || call.arguments.length !== 0)
6325
+ if (access.name.text !== "toString" || call.arguments.length > 1 || call.arguments.some(ts.isSpreadElement))
5579
6326
  return null;
5580
6327
  const recvKind = lowerer.mapTypeOf(lowerer.typeOf(access.expression))?.kind;
5581
6328
  if (recvKind !== "f64" && recvKind !== "bool" && recvKind !== "string")
@@ -5583,6 +6330,22 @@ function lowerNumberToStringCall(lowerer, call, access) {
5583
6330
  if (!lowerer.isStdlibMember(access))
5584
6331
  return null;
5585
6332
  const operand = lowerer.lowerExpr(access.expression);
6333
+ // JavaScript array and typed-array reads can still be undefined even
6334
+ // when the checker declares a number. Preserve that runtime value and
6335
+ // let native method dispatch format numbers or throw for missing data.
6336
+ if (operand.type.kind === "dyn") {
6337
+ return {
6338
+ kind: "libCall", fn: "dyn.toString", args: [operand,
6339
+ call.arguments[0] ? lowerer.lowerExprExpecting(call.arguments[0], DYN) : dynUndefinedExpr(locOf(call)),
6340
+ { kind: "strLit", value: access.getText(), type: STRING, loc: locOf(call) },
6341
+ ], type: STRING, loc: locOf(call),
6342
+ };
6343
+ }
6344
+ if (call.arguments.length === 1) {
6345
+ if (operand.type.kind !== "f64")
6346
+ return null;
6347
+ return { kind: "libCall", fn: "num.toStringRadix", args: [operand, lowerer.lowerExprExpecting(call.arguments[0], DYN)], type: STRING, loc: locOf(call) };
6348
+ }
5586
6349
  if (operand.type.kind === "string")
5587
6350
  return operand; // identity, receiver evaluated
5588
6351
  if (operand.type.kind !== "f64" && operand.type.kind !== "bool")
@@ -5727,6 +6490,13 @@ function lowerClassHasOwnPropertyCall(lowerer, call, access) {
5727
6490
  else
5728
6491
  return null; // computed static names — the answer isn't static
5729
6492
  }
6493
+ if (!own.has(key)) {
6494
+ const loc = locOf(call);
6495
+ const data = classStaticDataFor(lowerer, info, key, loc);
6496
+ if (data)
6497
+ return { kind: "libCall", fn: "dyn.hasOwn", args: [data,
6498
+ { kind: "strLit", value: key, type: STRING, loc }], type: BOOL, loc };
6499
+ }
5730
6500
  return { kind: "boolLit", value: own.has(key), type: BOOL, loc: locOf(call) };
5731
6501
  }
5732
6502
  /** Side-effect-free receiver test for the CONSTANT primitive-prototype
@@ -5941,6 +6711,12 @@ function implicitReceiverOverloadReturn(lowerer, expr) {
5941
6711
  function reconcileOverloadReturn(lowerer, expr, call) {
5942
6712
  const rsig = lowerer.checker.getResolvedSignature(expr);
5943
6713
  const rdecl = rsig ? lowerer.checker.signatureDeclaration(rsig) : undefined;
6714
+ // Fluent JS overrides share the base's return ABI, but their result
6715
+ // still has the receiver's subclass layout at the call site.
6716
+ if (call.type.kind === "object" && rdecl && ts.isMethodDeclaration(rdecl) &&
6717
+ isJsSourceFile(rdecl.getSourceFile()) && returnsOnlyThis(rdecl)) {
6718
+ call = lowerer.maybeNarrow(call, expr);
6719
+ }
5944
6720
  const resolvedOverload = rsig && rdecl &&
5945
6721
  (ts.isFunctionDeclaration(rdecl) || ts.isMethodDeclaration(rdecl)) &&
5946
6722
  !rdecl.body
@@ -6032,15 +6808,14 @@ function templateEscapesValid(raw) {
6032
6808
  * maps to string[] (type-mapper.ts), so the array rides the ordinary
6033
6809
  * slot-directed coercion into whatever the tag's first parameter wants
6034
6810
  * — string[] exactly, an `any` slot through the dyn boundary, a rest
6035
- * pack's first element. `.raw` does not exist on the lowered object:
6036
- * reads fence per member, and String.raw itself lowered above (the raw
6037
- * spans splice directly, no array materializes).
6811
+ * pack's first element. Checked tags receive frozen cooked and raw
6812
+ * arrays with the standard nonenumerable `.raw` descriptor. Typed direct
6813
+ * tags retain the string-array representation.
6038
6814
  *
6039
6815
  * Tag forms: a top-level declared function (the direct-call fast path —
6040
6816
  * overload sets reconcile through the resolved signature exactly like
6041
6817
  * plain calls), an island value under --dynamic (engine method/function
6042
- * call: the engine side sees a plain marshaled array — a tag reading
6043
- * `.raw` there answers undefined where Node carries the raw spans), and
6818
+ * call with the engine's cooked/raw template object), and
6044
6819
  * a checked-dynamic value (the dynCall boundary — a non-function tag
6045
6820
  * throws Node's catchable TypeError). Everything else — generic tags,
6046
6821
  * method tags, function-value bindings — fences by name. */
@@ -6100,10 +6875,11 @@ export function lowerTaggedTemplate(lowerer, expr) {
6100
6875
  if (ts.isIdentifier(expr.tag) && !lowerer.isSelfReference(expr.tag)) {
6101
6876
  if (lowerer.isTopLevelFnSymbol(expr.tag) && !lowerer.peekLocal(expr.tag)) {
6102
6877
  fenceEarlyAliasUse(lowerer, expr.tag, expr);
6103
- if (lowerer.genericFnOf(expr.tag)) {
6878
+ const genericTag = lowerer.genericFnOf(expr.tag);
6879
+ if (genericTag && !genericTag.implicitParams) {
6104
6880
  lowerer.unsupported("SC1090", expr, "tagged templates with generic tag functions");
6105
6881
  }
6106
- const sig = lowerer.fnSigOf(expr.tag);
6882
+ const sig = genericTag ? null : lowerer.fnSigOf(expr.tag);
6107
6883
  if (sig) {
6108
6884
  lowerer.noteEdge(sig.name);
6109
6885
  const args = completeArgs(lowerer, values, sig.params, loc, expr, [strings()]);
@@ -6130,10 +6906,13 @@ export function lowerTaggedTemplate(lowerer, expr) {
6130
6906
  // Checked-dynamic tags (`var f: any; f\`abc\``, dyn property chains):
6131
6907
  // the dynCall boundary — arguments convert into dyn, a non-function
6132
6908
  // tag throws Node's catchable "<name> is not a function" TypeError.
6133
- const callee = lowerer.lowerExpr(expr.tag);
6909
+ let callee = lowerer.lowerExpr(expr.tag);
6910
+ if (callee.type.kind === "func" && isJsSourceFile(expr.getSourceFile()) && lowerer.dynConvertible(callee.type)) {
6911
+ callee = { kind: "dynFrom", value: callee, type: DYN, loc };
6912
+ }
6134
6913
  if (callee.type.kind === "dyn") {
6135
6914
  const args = [
6136
- lowerer.coerceInto(expr.template, strings(), DYN),
6915
+ loweredTemplateStrings(lowerer, expr, pieces.map((piece) => piece.text), loc, pieces.map(templateRawTextOf)),
6137
6916
  ...values.map((a) => lowerer.lowerExprExpecting(a, DYN)),
6138
6917
  ];
6139
6918
  const calleeName = ts.isPropertyAccessExpression(expr.tag) || ts.isElementAccessExpression(expr.tag)
@@ -6145,12 +6924,15 @@ export function lowerTaggedTemplate(lowerer, expr) {
6145
6924
  }
6146
6925
  lowerer.unsupported("SC1090", expr, "tagged templates with this tag form (top-level functions and dynamic values tag; call the function directly otherwise)");
6147
6926
  }
6148
- function loweredTemplateStrings(lowerer, expr, cooked, loc) {
6927
+ function loweredTemplateStrings(lowerer, expr, cooked, loc, raw) {
6149
6928
  // Normal runtime construction keeps this array aligned with the current
6150
- // ScrArr layout in both backends. The old static-header IR node encoded the
6929
+ // ScrArr layout in the backend. The old static-header IR node encoded the
6151
6930
  // pre-sparse layout in LLVM and crashed as soon as a tag read its strings.
6152
- const type = arrayOf(STRING);
6153
- const key = `templateStringsGlobal:${loc.file}:${expr.template.getStart()}`;
6931
+ const type = raw ? DYN : arrayOf(STRING);
6932
+ const array = (values) => ({ kind: "dynArrLit", elems: values.map((value) => ({ kind: "dynFrom", value: { kind: "strLit", value, type: STRING, loc }, type: DYN, loc })), type: DYN, loc });
6933
+ const freeze = (value) => ({ kind: "libCall", fn: "dyn.freeze", args: [value], type: DYN, loc });
6934
+ const checked = raw ? freeze({ kind: "libCall", fn: "dyn.defineProperty", args: [array(cooked), { kind: "dynFrom", value: { kind: "strLit", value: "raw", type: STRING, loc }, type: DYN, loc }, { kind: "dynObjLit", fields: [{ key: { kind: "strLit", value: "value", type: STRING, loc }, value: freeze(array(raw)) }], type: DYN, loc }], type: DYN, loc }) : null;
6935
+ const key = `templateStringsGlobal:${loc.file}:${expr.template.getStart()}:${raw ? "checked" : "typed"}`;
6154
6936
  let getter = lowerer.widthHelpers.get(key);
6155
6937
  if (!getter) {
6156
6938
  const site = lowerer.globalsList.length;
@@ -6172,7 +6954,7 @@ function loweredTemplateStrings(lowerer, expr, cooked, loc) {
6172
6954
  {
6173
6955
  kind: "assign",
6174
6956
  localId: globalId,
6175
- value: {
6957
+ value: checked ?? {
6176
6958
  kind: "arrayLit",
6177
6959
  elems: cooked.map((value) => ({ kind: "strLit", value, type: STRING, loc })),
6178
6960
  type,
@@ -6204,7 +6986,7 @@ export function isTopLevelFnSymbol(lowerer, ident) {
6204
6986
  const decl = symbol ? lowerer.checker.declarationsOf(symbol)[0] : undefined;
6205
6987
  return (!!decl &&
6206
6988
  ts.isFunctionDeclaration(decl) &&
6207
- (ts.isSourceFile(decl.parent) || lowerer.nsBlocks.get(decl.parent) === "flattened"));
6989
+ (ts.isSourceFile(decl.parent) || (decl.parent !== undefined && lowerer.nsBlocks.get(decl.parent) === "flattened")));
6208
6990
  }
6209
6991
  /** Nested `function name(...) {...}`: declare the mutable function binding
6210
6992
  * before lowering its body, then initialize it with the lifted closure.
@@ -6246,6 +7028,22 @@ export function lowerNestedFunctionDecl(lowerer, stmt) {
6246
7028
  export function lambdaSignature(lowerer, node) {
6247
7029
  if (!node.body)
6248
7030
  lowerer.unsupported("SC1090", node, "function overload signatures");
7031
+ // A JS replacement of a native stream's write method receives the
7032
+ // actual call tuple, including overloads and omitted arguments. Node's
7033
+ // contextual overload signature cannot define this closure's ABI.
7034
+ if (isJsSourceFile(node.getSourceFile()) && !node.type &&
7035
+ (ts.isFunctionExpression(node) || ts.isArrowFunction(node)) &&
7036
+ node.parameters.every((param) => !param.type && !param.dotDotDotToken && !param.initializer) &&
7037
+ ts.isBinaryExpression(node.parent) && node.parent.right === node &&
7038
+ node.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
7039
+ ts.isPropertyAccessExpression(node.parent.left) && node.parent.left.name.text === "write" &&
7040
+ lowerer.isStdlibMember(node.parent.left)) {
7041
+ const receiver = lowerer.lowerExpr(node.parent.left.expression);
7042
+ if (receiver.type.kind === "dyn") {
7043
+ const shapes = node.parameters.map(() => ({ type: DYN, mode: "required" }));
7044
+ return { shapes, funcType: funcTypeFromParamShapes(shapes, DYN) };
7045
+ }
7046
+ }
6249
7047
  if (node.typeParameters) {
6250
7048
  // Generic function-like forms monomorphize only where a static home
6251
7049
  // exists: top-level generic function declarations, generic methods
@@ -6261,6 +7059,23 @@ export function lambdaSignature(lowerer, node) {
6261
7059
  : "generic arrow/function expressions outside a never-reassigned module-scope binding (only `const f = <T>(x: T) => ...` bindings and top-level generic function declarations monomorphize)");
6262
7060
  }
6263
7061
  const shapes = lowerer.paramShapes(node.parameters);
7062
+ // Error-first callbacks captured by native filesystem adapters receive
7063
+ // the selected runtime overload. Ambient contextual inference can pick
7064
+ // the string overload even when options request a Buffer.
7065
+ if ((ts.isArrowFunction(node) || ts.isFunctionExpression(node)) && ts.isCallExpression(node.parent) &&
7066
+ node.parent.arguments.at(-1) === node) {
7067
+ const builtin = ts.isPropertyAccessExpression(node.parent.expression) ? lowerer.builtinMemberOf(node.parent.expression)
7068
+ : ts.isIdentifier(node.parent.expression) ? lowerer.builtinImportOf(node.parent.expression) : null;
7069
+ if (builtin?.module === "fs" && builtin.member !== "rename" && builtinModuleFnOf(lowerer, builtin.module, builtin.member)?.fn === "fs.callbackCall") {
7070
+ for (let index = 0; index < shapes.length; index++) {
7071
+ if (!node.parameters[index]?.type) {
7072
+ shapes[index].type = DYN;
7073
+ if (shapes[index].bodyType)
7074
+ shapes[index].bodyType = DYN;
7075
+ }
7076
+ }
7077
+ }
7078
+ }
6264
7079
  // A concise arrow over an h2-only stream/session call (`() =>
6265
7080
  // req.stream.destroy()`): the call ALWAYS throws on this lowering
6266
7081
  // (stream is undefined — the streamUndefCall precedent), so the body
@@ -6271,8 +7086,8 @@ export function lambdaSignature(lowerer, node) {
6271
7086
  : lowerer.declaredReturnType(node, node);
6272
7087
  ret = lowerer.runtimeOptionalFunctionReturnType(node, ret);
6273
7088
  // A contextually-typed arrow/function EXPRESSION whose slot signature
6274
- // returns a UNION the inferred return doesn't spell adopts the slot's
6275
- // return as its ABI: `(n) => work()` (inferring Promise<void>) against
7089
+ // returns a composite type the inferred return doesn't spell adopts
7090
+ // the slot's return as its ABI: `(n) => work()` (inferring Promise<void>) against
6276
7091
  // an `(n) => Promise<void> | void` field must RETURN that union — the
6277
7092
  // body's returns coerce into it per return site (arm values wrap;
6278
7093
  // width-coercible records rebuild into their arm — the runJobs
@@ -6286,6 +7101,9 @@ export function lambdaSignature(lowerer, node) {
6286
7101
  // returns coerce; the spawn-wrapper ABI still returns a promise).
6287
7102
  // jsval-returning bodies stay out (adoption would force validated
6288
7103
  // exits the writer never asked for).
7104
+ // Array and record returns also need the destination during literal
7105
+ // construction: a callback building IrStmt[] must wrap each element at
7106
+ // that recursive layout instead of first inferring narrower arrays.
6289
7107
  const isAsyncLike = !ts.isMethodDeclaration(node) &&
6290
7108
  node.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) === true;
6291
7109
  const innerRet = isAsyncLike && ret.kind === "promise" ? ret.inner : ret;
@@ -6310,8 +7128,8 @@ export function lambdaSignature(lowerer, node) {
6310
7128
  ? lowerer.mapTypeOf(lowerer.checker.getReturnTypeOfSignature(ctxSigs[0]))
6311
7129
  : null;
6312
7130
  const ctxRet = isAsyncLike && ctxRetRaw?.kind === "promise" ? ctxRetRaw.inner : ctxRetRaw;
6313
- if (ctxRet?.kind === "union" &&
6314
- (innerRet.kind === "void" ? lowerer.armTag(ctxRet.unionId, UNDEFINED_T) >= 0 : true)) {
7131
+ if ((ctxRet?.kind === "union" || ctxRet?.kind === "array" || ctxRet?.kind === "record") &&
7132
+ (innerRet.kind !== "void" || (ctxRet.kind === "union" && lowerer.armTag(ctxRet.unionId, UNDEFINED_T) >= 0))) {
6315
7133
  ret = isAsyncLike ? { kind: "promise", inner: ctxRet } : ctxRet;
6316
7134
  }
6317
7135
  // A VOID slot discards the callback's result (TS's void-returning
@@ -6331,38 +7149,48 @@ export function lambdaSignature(lowerer, node) {
6331
7149
  ret = VOID;
6332
7150
  }
6333
7151
  }
7152
+ ret = lowerer.contextualFunctionReturns.get(node) ?? ret;
6334
7153
  // A plain JS function reading `arguments` receives one hidden dyn
6335
7154
  // array. With named parameters, the array contains every actual
6336
7155
  // argument and only ES modules are admitted: sloppy-mode arguments
6337
7156
  // alias named parameters. Arrows inherit the enclosing `arguments`.
6338
7157
  const hasRest = shapes.some((s) => s.mode === "rest" || s.mode === "dynRest" || s.mode === "islandRest");
6339
7158
  const usesArguments = !hasRest &&
6340
- (ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node)) &&
7159
+ (ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) &&
6341
7160
  isJsSourceFile(node.getSourceFile()) &&
6342
7161
  bodyReadsArguments(node);
6343
- if (usesArguments && node.parameters.length > 0) {
6344
- if (!isNodeEsmFile(node.getSourceFile())) {
6345
- lowerer.unsupported("SC1090", node, "parameterized 'arguments' outside an ES module (sloppy-mode parameter aliases)");
7162
+ if (usesArguments) {
7163
+ if (node.parameters.length > 0 || ts.isMethodDeclaration(node)) {
7164
+ const classMethod = ts.isMethodDeclaration(node) &&
7165
+ (ts.isClassDeclaration(node.parent) || ts.isClassExpression(node.parent));
7166
+ if (!classMethod && !isNodeEsmFile(node.getSourceFile(), lowerer.program)) {
7167
+ lowerer.unsupported("SC1090", node, "parameterized 'arguments' outside an ES module (sloppy-mode parameter aliases)");
7168
+ }
6346
7169
  }
6347
7170
  shapes.push({ type: DYN, mode: "arguments" });
6348
7171
  }
6349
7172
  const funcType = funcTypeFromParamShapes(shapes, ret);
6350
- if (usesArguments)
6351
- funcType.rest = true;
6352
7173
  return { shapes, funcType };
6353
7174
  }
6354
7175
  /** Lifts an arrow function / function expression / nested declaration /
6355
7176
  * object-literal shorthand method to a module-level function and yields
6356
7177
  * the `closure` expression creating it. */
6357
7178
  export function lowerLambda(lowerer, node) {
7179
+ const prepared = (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) ? lowerer.preparedClassFactories.get(node) : undefined;
7180
+ if (prepared)
7181
+ return prepared;
6358
7182
  const loc = locOf(node);
6359
- const { shapes, funcType } = lowerer.lambdaSignature(node);
7183
+ const signature = lowerer.lambdaSignature(node);
7184
+ const { shapes } = signature;
7185
+ let { funcType } = signature;
6360
7186
  // A lambda IS a value: the completed-ABI rule applies at birth. The
6361
7187
  // contextual (target) type decides — `(x?: number) => void` may flow
6362
7188
  // into a slot annotated `(x: number | undefined) => void` (same ABI
6363
7189
  // signature), anything else is fenced. Nested function declarations and
6364
7190
  // object-literal shorthand methods aren't expressions — always fenced.
6365
- lowerer.requireExactArityValue(node, ts.isArrowFunction(node) || ts.isFunctionExpression(node) ? node : null, shapes, funcType);
7191
+ if (!(ts.isMethodDeclaration(node) && isJsSourceFile(node.getSourceFile()) &&
7192
+ canBoxFuncIntoDyn(funcType, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))))
7193
+ lowerer.requireExactArityValue(node, ts.isArrowFunction(node) || ts.isFunctionExpression(node) ? node : null, shapes, funcType);
6366
7194
  const nameIdent = !ts.isArrowFunction(node) && node.name && ts.isIdentifier(node.name) ? node.name : null;
6367
7195
  const baseName = nameIdent ? nameIdent.text : "";
6368
7196
  const fnName = `%fn${lowerer.lambdaCounter++}${baseName ? `_${baseName}` : ""}`;
@@ -6386,10 +7214,18 @@ export function lowerLambda(lowerer, node) {
6386
7214
  if (isGenerator &&
6387
7215
  (funcType.ret.kind !== "generator" || (funcType.ret.async === true) !== isAsync))
6388
7216
  lowerer.badType(node, lowerer.typeOf(node));
6389
- const bodyReturn = isGenerator
7217
+ let bodyReturn = isGenerator
6390
7218
  ? lowerer.genBodyReturnType(funcType.ret)
6391
7219
  : lowerer.bodyReturnType(isAsync, funcType.ret);
6392
7220
  const fnCtx = newFnCtx(true, selfSymbol, funcType, bodyReturn);
7221
+ const inferredSignature = isJsSourceFile(node.getSourceFile()) && !node.type ? lowerer.checker.getSignatureFromDeclaration(node) : undefined;
7222
+ const returnsConstructor = inferredSignature && producesConstructor(lowerer, lowerer.checker.getReturnTypeOfSignature(inferredSignature));
7223
+ if (isJsSourceFile(node.getSourceFile()) && !node.type && !isAsync && !isGenerator &&
7224
+ (bodyReturn.kind === "classval" || bodyReturn.kind === "date" || bodyReturn.kind === "symbol" || bodyReturn.kind === "record" ||
7225
+ (bodyReturn.kind === "dyn" || bodyReturn.kind === "func") && returnsConstructor)) {
7226
+ fnCtx.inferReturn = { entries: [] };
7227
+ }
7228
+ fnCtx.inheritsArguments = ts.isArrowFunction(node);
6393
7229
  fnCtx.isAsync = isAsync;
6394
7230
  if (isGenerator && funcType.ret.kind === "generator") {
6395
7231
  fnCtx.generator = generatorMeta(lowerer, funcType.ret);
@@ -6398,14 +7234,30 @@ export function lowerLambda(lowerer, node) {
6398
7234
  lowerer.fnStack.push(fnCtx);
6399
7235
  try {
6400
7236
  const { params, prologue } = lowerer.declareParams(node.parameters, shapes);
7237
+ // Checked JavaScript functions take their receiver from the call site.
7238
+ // Store it as this function's binding so escaping arrows capture it,
7239
+ // and a method nested inside another method never captures its owner.
7240
+ if (isJsSourceFile(node.getSourceFile()) && !ts.isArrowFunction(node)) {
7241
+ const receiver = lowerer.declareThis(DYN);
7242
+ prologue.unshift({ kind: "varDecl", localId: receiver.id, init: { kind: "libCall", fn: isGenerator ? "dyn.generatorThis" : "dyn.this", args: [], type: DYN, loc }, loc });
7243
+ }
6401
7244
  // The synthetic trailing dyn-array param carries `arguments`.
6402
7245
  // Parameterized functions receive all actual arguments; zero-param
6403
7246
  // functions receive the same array through their rest ABI.
6404
- if (funcType.rest && !shapes.some((s) => s.mode === "dynRest" || s.mode === "islandRest")) {
7247
+ if (funcType.rest && funcType.restAbi === undefined && !shapes.some((s) => s.mode === "dynRest" || s.mode === "islandRest")) {
6405
7248
  const argsLocal = lowerer.declareHiddenLocal("%arguments", DYN);
6406
7249
  params.push({ localId: argsLocal.id, name: "%arguments", type: DYN });
6407
7250
  fnCtx.argumentsLocal = argsLocal;
6408
7251
  }
7252
+ if (isJsSourceFile(node.getSourceFile()) && !ts.isArrowFunction(node) &&
7253
+ shapes.length === 1 && shapes[0]?.mode === "dynRest" && bodyReadsArguments(node)) {
7254
+ const argsLocal = lowerer.declareHiddenLocal("%arguments", DYN);
7255
+ prologue.push({ kind: "varDecl", localId: argsLocal.id, init: {
7256
+ kind: "dynInvoke", recv: varRef(params[0].localId, DYN, loc), method: "slice",
7257
+ calleeName: "Array.prototype.slice", args: [], type: DYN, loc,
7258
+ }, loc });
7259
+ fnCtx.argumentsLocal = argsLocal;
7260
+ }
6409
7261
  let body;
6410
7262
  if (ts.isBlock(node.body)) {
6411
7263
  body = lowerer.lowerStmts(node.body.statements);
@@ -6438,7 +7290,9 @@ export function lowerLambda(lowerer, node) {
6438
7290
  }
6439
7291
  }
6440
7292
  else {
6441
- let value = lowerer.lowerExpr(bodyExpr);
7293
+ // Concise and block bodies use the same destination layout for
7294
+ // fresh literals. Async bodies must inspect promises first.
7295
+ let value = isAsync || fnCtx.inferReturn ? lowerer.lowerExpr(bodyExpr) : lowerer.lowerExprExpecting(bodyExpr, bodyReturn);
6442
7296
  // An async concise body whose value is itself a promise
6443
7297
  // (`async () => p`): the async machinery RESOLVES the returned
6444
7298
  // thenable into the function's own promise — lowerReturnValue's
@@ -6452,22 +7306,32 @@ export function lowerLambda(lowerer, node) {
6452
7306
  : [
6453
7307
  {
6454
7308
  kind: "return",
6455
- value: lowerer.coerceInto(bodyExpr, value, bodyReturn),
7309
+ value: fnCtx.inferReturn ? value : lowerer.coerceInto(bodyExpr, value, bodyReturn),
6456
7310
  loc: locOf(node.body),
6457
7311
  },
6458
7312
  ];
7313
+ if (fnCtx.inferReturn && body[0]?.kind === "return")
7314
+ fnCtx.inferReturn.entries.push({ stmt: body[0], node: bodyExpr });
6459
7315
  }
6460
7316
  }
7317
+ if (fnCtx.inferReturn) {
7318
+ bodyReturn = resolveInferredReturn(lowerer, { returnType: bodyReturn }, fnCtx.inferReturn, body, node);
7319
+ funcType = { ...funcType, ret: bodyReturn };
7320
+ fnCtx.returnType = bodyReturn;
7321
+ }
6461
7322
  body = [...prologue, ...body];
6462
7323
  // Bare-expression bodies never pass through lowerStmts, so the
6463
7324
  // lib-boundary chokepoint runs here (idempotent for block bodies,
6464
7325
  // whose statements were already walked). A fence poisons the
6465
7326
  // enclosing statement — the lambda IS part of it.
7327
+ body = lowerSurplusCalls(lowerer, body);
6466
7328
  enforceLibBoundary(lowerer, body);
6467
7329
  appendImplicitUndefinedReturn(lowerer, body, bodyReturn, loc);
6468
7330
  const ctx = lowerer.ctx;
6469
7331
  const lifted = {
6470
7332
  name: fnName,
7333
+ sourceName: jsFuncNameOf(node) ?? "<anonymous>",
7334
+ ...(!isAsync && !isGenerator && (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node)) ? { ownsPrototype: true } : {}),
6471
7335
  params,
6472
7336
  returnType: bodyReturn,
6473
7337
  locals: ctx.locals,
@@ -6614,7 +7478,7 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
6614
7478
  const member = access.name.text;
6615
7479
  if (member !== "then" && member !== "catch" && member !== "finally")
6616
7480
  return null;
6617
- let recvT = lowerer.mapTypeOf(lowerer.typeOf(access.expression));
7481
+ let recvT = lowerer.mapTypeOf(lowerer.typeOf(access.expression)) ?? dynFallbackType(lowerer, access.expression, lowerer.typeOf(access.expression));
6618
7482
  // A dynamic-import promise under an unmappable checker type
6619
7483
  // (`Promise<typeof import("./m")>` — module-namespace types have no
6620
7484
  // static mapping): the BINDING holds the island promise
@@ -6667,6 +7531,8 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
6667
7531
  loc,
6668
7532
  };
6669
7533
  }
7534
+ if (receiver.type.kind === "dyn" && lowerer.dynConvertible(recvT))
7535
+ receiver = lowerer.coerceInto(access.expression, receiver, recvT);
6670
7536
  if (receiver.type.kind !== "promise") {
6671
7537
  // mapTypeOf said promise but the value lowered as something else —
6672
7538
  // a lowering gap, named rather than ICEd on.
@@ -6810,10 +7676,12 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
6810
7676
  }));
6811
7677
  }
6812
7678
  else {
7679
+ if (settled.type.kind !== "dyn" &&
7680
+ !canConvertToDyn(settled.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
7681
+ lowerer.unsupported("SC1090", fulfilledNode, "then fulfillment values that cannot cross the checked-dynamic boundary");
7682
+ }
6813
7683
  const arg = settled.type.kind === "dyn" ? settled
6814
- : canConvertToDyn(settled.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))
6815
- ? { kind: "dynFrom", value: settled, type: DYN, loc }
6816
- : lowerer.unsupported("SC1090", fulfilledNode, "then fulfillment values that cannot cross the checked-dynamic boundary");
7684
+ : { kind: "dynFrom", value: settled, type: DYN, loc };
6817
7685
  body.push(...resultOf({
6818
7686
  kind: "dynCall",
6819
7687
  callee: { kind: "varRef", localId: fLocal.id, type: DYN, loc },
@@ -6957,7 +7825,7 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
6957
7825
  lowerer.unsupported("SC1090", call.arguments[0], "then handlers with more than one parameter (the two-argument onRejected form has no lowering — chain .catch(...) instead)");
6958
7826
  }
6959
7827
  const param = cb.type.params[0];
6960
- if (param !== undefined && !typeEquals(param, inner)) {
7828
+ if (param !== undefined && !typeEquals(param, inner) && !(inner.kind === "void" && param.kind === "dyn")) {
6961
7829
  lowerer.unsupported("SC1090", call.arguments[0], `then handlers whose parameter is not the settled value's type (expected '${lowerer.fmt(inner)}', got '${lowerer.fmt(param)}')`);
6962
7830
  }
6963
7831
  const resultT = lowerer.mapTypeOf(lowerer.typeOf(call));
@@ -6991,6 +7859,8 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
6991
7859
  }
6992
7860
  else {
6993
7861
  body.push({ kind: "exprStmt", expr: awaitE, loc });
7862
+ if (param !== undefined)
7863
+ handlerArgs = [dynUndefinedExpr(loc)];
6994
7864
  }
6995
7865
  const handlerCall = {
6996
7866
  kind: "callValue",
@@ -7677,7 +8547,8 @@ export function recordKeysArrayCall(lowerer, receiver, argIr, shape, loc) {
7677
8547
  loc,
7678
8548
  };
7679
8549
  const finalize = () => {
7680
- const current = lowerer.shapes.get(argIr.shapeId) ?? shape;
8550
+ const latest = lowerer.shapes.get(argIr.shapeId);
8551
+ const current = latest !== undefined ? latest : shape;
7681
8552
  const body = [
7682
8553
  { kind: "varDecl", localId: "out.0", init: { kind: "arrayLit", elems: [], type: resultT, loc }, loc },
7683
8554
  ];
@@ -7727,10 +8598,11 @@ export function recordKeysArrayCall(lowerer, receiver, argIr, shape, loc) {
7727
8598
  return { kind: "call", callee: helper, args: [receiver], type: resultT, loc };
7728
8599
  }
7729
8600
  /** Interned `%obj.hasOwn.<n>(r, k)` — Object.hasOwn's membership walk
7730
- * over a signature-free record shape: the key compares against each
8601
+ * over a record shape: the key compares against each
7731
8602
  * declared field name, undefined-armed fields answering by their tag
7732
8603
  * (a key is own exactly when Object.keys would list it — the two share
7733
- * the guard), everything else true, no match false. */
8604
+ * the guard), everything else true. Unmatched keys probe the overflow
8605
+ * map when present, so explicit undefined values remain own keys. */
7734
8606
  function recordHasOwnHelper(lowerer, shapeId, loc) {
7735
8607
  const key = `obj.hasOwn:${shapeId}`;
7736
8608
  const existing = lowerer.arrHofHelpers.get(key);
@@ -7764,7 +8636,10 @@ function recordHasOwnHelper(lowerer, shapeId, loc) {
7764
8636
  loc,
7765
8637
  });
7766
8638
  }
7767
- body.push({ kind: "return", value: { kind: "boolLit", value: false, type: BOOL, loc }, loc });
8639
+ const fallback = shape.indexValue
8640
+ ? { kind: "recordOvfHas", obj: rRef, shapeId, key: kRef, type: BOOL, loc }
8641
+ : { kind: "boolLit", value: false, type: BOOL, loc };
8642
+ body.push({ kind: "return", value: fallback, loc });
7768
8643
  lowerer.liftedFns.push({
7769
8644
  name: helper,
7770
8645
  params: [
@@ -7944,6 +8819,44 @@ function lowerObjectStaticCall(lowerer, call, access) {
7944
8819
  if (!lowerer.isStdlibGlobal(access.expression, "Object"))
7945
8820
  return null;
7946
8821
  const member = access.name.text;
8822
+ if ((member === "getOwnPropertyNames" || member === "getOwnPropertySymbols" || member === "getOwnPropertyDescriptors") && call.arguments.length === 1 &&
8823
+ !call.arguments.some(ts.isSpreadElement) && !lowerer.dynamic) {
8824
+ let object = lowerer.lowerExpr(call.arguments[0]);
8825
+ if (object.type.kind === "string" || object.type.kind === "f64" ||
8826
+ object.type.kind === "bool" || isUnitType(object.type))
8827
+ object = { kind: "dynFrom", value: object, type: DYN, loc: locOf(call) };
8828
+ if (object.type.kind === "dyn")
8829
+ return { kind: "libCall", fn: member === "getOwnPropertyNames" ? "dyn.getOwnPropertyNames" : member === "getOwnPropertySymbols" ? "dyn.getOwnPropertySymbols" : "dyn.getOwnPropertyDescriptors", args: [object], type: DYN, loc: locOf(call) };
8830
+ }
8831
+ if ((member === "getPrototypeOf" || member === "setPrototypeOf") &&
8832
+ call.arguments.length === (member === "getPrototypeOf" ? 1 : 2) &&
8833
+ !call.arguments.some(ts.isSpreadElement) && !lowerer.dynamic) {
8834
+ let object = lowerer.lowerExpr(call.arguments[0]);
8835
+ if (object.type.kind === "func") {
8836
+ const fnName = jsFuncNameOf(call.arguments[0]);
8837
+ object = { kind: "dynFrom", value: object, type: DYN, loc: locOf(call),
8838
+ ...(fnName !== null ? { fnName } : {}) };
8839
+ }
8840
+ if (object.type.kind !== "dyn" && canConvertToDyn(object.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id)))
8841
+ object = lowerer.coerceInto(call.arguments[0], object, DYN);
8842
+ if (object.type.kind === "dyn") {
8843
+ const loc = locOf(call);
8844
+ if (member === "getPrototypeOf")
8845
+ return { kind: "libCall", fn: "dyn.getPrototype", args: [object], type: DYN, loc };
8846
+ const prototype = lowerer.lowerExprExpecting(call.arguments[1], DYN);
8847
+ if (prototype.type.kind === "dyn")
8848
+ return { kind: "libCall", fn: "dyn.setPrototype", args: [object, prototype], type: DYN, loc };
8849
+ }
8850
+ }
8851
+ if (member === "getOwnPropertyDescriptor" && call.arguments.length === 2) {
8852
+ const [receiver, key] = call.arguments;
8853
+ if (receiver && key && ts.isPropertyAccessExpression(receiver) && receiver.name.text === "prototype" &&
8854
+ lowerer.isStdlibGlobal(receiver.expression, "ArrayBuffer") && ts.isStringLiteral(key) && key.text === "byteLength") {
8855
+ const loc = locOf(call);
8856
+ const getter = lowerer.lowerNativeCallableValue({ fn: "arrayBuffer.byteLengthGetter", params: [], result: F64, valueParams: [] }, "get ArrayBuffer.prototype.byteLength", loc);
8857
+ return { kind: "libCall", fn: "arrayBuffer.byteLengthDescriptor", args: [lowerer.coerceToExpected(getter, DYN)], type: DYN, loc };
8858
+ }
8859
+ }
7947
8860
  const cacheKeys = lowerRequireCacheKeys(lowerer, call, member);
7948
8861
  if (cacheKeys)
7949
8862
  return cacheKeys;
@@ -7982,7 +8895,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
7982
8895
  if (unitTest)
7983
8896
  return unitTest;
7984
8897
  if (lk === "dyn" || rk === "dyn" || lk === "jsval" || rk === "jsval") {
7985
- lowerer.noLowering("Object.is over a dynamic operand", call, "validate/narrow the value first (strict equality's rule) — SameValue only differs from === on numbers (NaN, ±0)");
8898
+ return { kind: "libCall", fn: "dyn.sameValue", args: [lowerer.coerceInto(leftNode, left, DYN), lowerer.coerceInto(rightNode, right, DYN)], type: BOOL, loc };
7986
8899
  }
7987
8900
  if (left.type.kind === "union" || right.type.kind === "union") {
7988
8901
  const ut = left.type.kind === "union" ? left.type : right.type;
@@ -8045,23 +8958,14 @@ function lowerObjectStaticCall(lowerer, call, access) {
8045
8958
  }
8046
8959
  lowerer.noLowering(`Object.is over '${lowerer.fmt(left.type)}' and '${lowerer.fmt(right.type)}' operands`, call, "the operands must share one comparable kind (numbers, strings, booleans, units, one union shape, or one reference type)");
8047
8960
  }
8048
- // Object.create — the null-prototype DICTIONARY (`Object.create(null)`
8049
- // then keyed assignment, the memo-table idiom prettier's index/
8050
- // group-mode maps spell) and, under --dynamic, the engine's own
8051
- // Object.create for engine-held prototypes. Everything else is a
8052
- // NAMED fence: the compiled representations have no prototype chain,
8053
- // and the own-copy stand-in would answer WRONG observably — Node's
8054
- // Object.keys/inspect/JSON of the created object list NO own keys,
8055
- // and mutating the prototype afterwards is visible through the
8056
- // created object (live delegation), which no copy can honor.
8961
+ // Native checked objects retain a live prototype and can install an
8962
+ // own-property descriptor table during creation. Engine-held values
8963
+ // use the engine's Object.create path below.
8057
8964
  if (member === "create") {
8058
8965
  if (call.arguments.some((a) => ts.isSpreadElement(a))) {
8059
8966
  lowerer.noLowering("Object.create with spread arguments", call);
8060
8967
  }
8061
- if (call.arguments.length >= 2) {
8062
- lowerer.noLowering("Object.create with a properties-descriptor argument", call, "create first, then assign: const o = Object.create(null); o.k = v");
8063
- }
8064
- if (call.arguments.length !== 1) {
8968
+ if (call.arguments.length < 1 || call.arguments.length > 2) {
8065
8969
  lowerer.noLowering(`Object.create with ${call.arguments.length} arguments`, call);
8066
8970
  }
8067
8971
  const loc = locOf(call);
@@ -8070,6 +8974,8 @@ function lowerObjectStaticCall(lowerer, call, access) {
8070
8974
  protoNode = protoNode.expression;
8071
8975
  const nullProto = protoNode.kind === ts.SyntaxKind.NullKeyword;
8072
8976
  if (lowerer.dynamic) {
8977
+ if (call.arguments.length === 2)
8978
+ lowerer.noLowering("Object.create with properties under --dynamic", call);
8073
8979
  // The checker types the result `any` — an ENGINE value under
8074
8980
  // --dynamic — and the engine's own Object.create answers with
8075
8981
  // REAL prototype semantics: reads delegate LIVE, writes shadow,
@@ -8090,15 +8996,41 @@ function lowerObjectStaticCall(lowerer, call, access) {
8090
8996
  }
8091
8997
  lowerer.noLowering(`Object.create over '${lowerer.fmt(proto.type)}' prototypes`, call, "prototype reads delegate LIVE in Node (mutating the prototype shows through the created object), which the boundary's deep copy cannot honor — only null and engine-held ('any') prototypes lower");
8092
8998
  }
8093
- if (nullProto) {
8999
+ if (nullProto && call.arguments.length === 1) {
8094
9000
  return { kind: "libCall", fn: "dyn.objCreateNullProto", args: [], type: DYN, loc };
8095
9001
  }
8096
- const proto = lowerer.lowerExpr(protoNode);
8097
- lowerer.noLowering(`Object.create over '${lowerer.fmt(proto.type)}' prototypes`, call, "the compiled representations have no prototype chain, and an own-copy would answer wrong observably (Node lists NO own keys on the created object, and prototype mutations show through it live) — only Object.create(null) lowers");
9002
+ let proto = nullProto
9003
+ ? { kind: "dynFrom", value: { kind: "unitLit", unit: "null", type: NULL_T, loc }, type: DYN, loc }
9004
+ : ts.isObjectLiteralExpression(protoNode)
9005
+ ? lowerer.lowerExprExpecting(protoNode, DYN)
9006
+ : lowerer.lowerExpr(protoNode);
9007
+ if (isUnitType(proto.type) || proto.type.kind === "f64" || proto.type.kind === "bool" || proto.type.kind === "string")
9008
+ proto = { kind: "dynFrom", value: proto, type: DYN, loc };
9009
+ if (proto.type.kind === "dyn") {
9010
+ if (call.arguments.length === 1)
9011
+ return { kind: "libCall", fn: "dyn.objCreate", args: [proto], type: DYN, loc };
9012
+ const descriptors = lowerer.lowerExprExpecting(call.arguments[1], DYN);
9013
+ if (descriptors.type.kind === "dyn")
9014
+ return { kind: "libCall", fn: "dyn.objCreateWithProperties", args: [proto, descriptors], type: DYN, loc };
9015
+ }
9016
+ lowerer.noLowering(`Object.create over '${lowerer.fmt(proto.type)}' prototypes`, call);
8098
9017
  }
8099
9018
  // `Object.assign(fn, { props })` whose RESULT type maps to the hybrid
8100
9019
  // (function-with-properties) record: the chalk-shape CONSTRUCTOR.
8101
9020
  if (member === "assign") {
9021
+ const prototype = lowerClassPrototypeAssign(lowerer, call);
9022
+ if (prototype)
9023
+ return prototype;
9024
+ if (isJsSourceFile(call.getSourceFile()) && call.arguments.length > 0 && !call.arguments.some(ts.isSpreadElement)) {
9025
+ const target = tryLowerExpression(lowerer, call.arguments[0]);
9026
+ if (target && ((target.type.kind === "func" && lowerer.dynConvertible(target.type)) ||
9027
+ (target.type.kind === "object" && lowerer.errorHierarchyClassOf(target.type.className)))) {
9028
+ const loc = locOf(call);
9029
+ return { kind: "libCall", fn: "dyn.assignAll", args: [lowerer.coerceToExpected(target, DYN),
9030
+ { kind: "dynArrLit", elems: call.arguments.slice(1).map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc },
9031
+ ], type: DYN, loc };
9032
+ }
9033
+ }
8102
9034
  const hybrid = lowerObjectAssignHybrid(lowerer, call);
8103
9035
  if (hybrid)
8104
9036
  return hybrid;
@@ -8145,7 +9077,9 @@ function lowerObjectStaticCall(lowerer, call, access) {
8145
9077
  if (tProbe?.type.kind === "dyn") {
8146
9078
  const loc = locOf(call);
8147
9079
  const target = lowerer.lowerExpr(call.arguments[0]);
8148
- const source = lowerer.coerceToExpected(lowerer.lowerExpr(call.arguments[1]), DYN);
9080
+ const rawSource = lowerer.lowerExpr(call.arguments[1]);
9081
+ fenceSymbolFieldCopy(lowerer, call.arguments[1], rawSource.type);
9082
+ const source = lowerer.coerceToExpected(rawSource, DYN);
8149
9083
  if (target.type.kind === "dyn" && source.type.kind === "dyn") {
8150
9084
  return { kind: "libCall", fn: "dyn.assign", args: [target, source], type: DYN, loc };
8151
9085
  }
@@ -8222,7 +9156,9 @@ function lowerObjectStaticCall(lowerer, call, access) {
8222
9156
  const argNode = sources[i];
8223
9157
  const spread = ts.isSpreadElement(argNode);
8224
9158
  const srcNode = spread ? argNode.expression : argNode;
8225
- const src = lowerer.coerceToExpected(lowerer.lowerExpr(srcNode), DYN);
9159
+ const rawSource = lowerer.lowerExpr(srcNode);
9160
+ fenceSymbolFieldCopy(lowerer, srcNode, rawSource.type, spread);
9161
+ const src = lowerer.coerceToExpected(rawSource, DYN);
8226
9162
  if (src.type.kind !== "dyn") {
8227
9163
  ok = false;
8228
9164
  break;
@@ -8259,22 +9195,82 @@ function lowerObjectStaticCall(lowerer, call, access) {
8259
9195
  }
8260
9196
  return null;
8261
9197
  }
9198
+ if ((member === "defineProperty" && call.arguments.length === 3) ||
9199
+ (member === "getOwnPropertyDescriptor" && call.arguments.length === 2)) {
9200
+ if (call.arguments.some((a) => ts.isSpreadElement(a)))
9201
+ return null;
9202
+ let target = tryLowerExpression(lowerer, call.arguments[0]);
9203
+ const targetNode = call.arguments[0];
9204
+ // The checker gives C.prototype the instance type, but its lowered
9205
+ // value is the shared prototype table, not an instance to unbox.
9206
+ const prototypeTarget = ts.isPropertyAccessExpression(targetNode) && targetNode.name.text === "prototype" &&
9207
+ (exactClassOfReceiver(lowerer, targetNode.expression) !== null || storedClassValueType(lowerer, targetNode.expression)?.kind === "classval");
9208
+ const declaredTarget = target?.type.kind === "dyn" && !prototypeTarget && !isJsSourceFile(targetNode.getSourceFile()) ? lowerer.mapTypeOf(lowerer.typeOf(targetNode)) : null;
9209
+ if (target && declaredTarget && isDynTypedRefType(declaredTarget))
9210
+ target = lowerer.coerceToExpected(target, declaredTarget);
9211
+ if (target && member === "defineProperty") {
9212
+ const native = lowerClassDataDescriptor(lowerer, call, member, target);
9213
+ if (native)
9214
+ return native;
9215
+ }
9216
+ if (target && member === "getOwnPropertyDescriptor" && isDynTypedRefType(target.type)) {
9217
+ const descriptor = lowerClassDescriptorRead(lowerer, call, target);
9218
+ if (descriptor)
9219
+ return descriptor;
9220
+ target = lowerer.coerceToExpected(target, DYN);
9221
+ }
9222
+ // Error instances share a live property table with their checked view.
9223
+ const keyNode = call.arguments[1];
9224
+ if (target?.type.kind === "object" && target.type.className !== "%DOMException" && lowerer.errorHierarchyClassOf(target.type.className) &&
9225
+ ((ts.isStringLiteral(keyNode) && (keyNode.text === "cause" || keyNode.text === "message")) || lowerer.mapTypeOf(lowerer.typeOf(keyNode))?.kind === "symbol")) {
9226
+ target = lowerer.coerceToExpected(target, DYN);
9227
+ }
9228
+ if (target?.type.kind === "func" && lowerer.dynConvertible(target.type)) {
9229
+ const fnName = jsFuncNameOf(call.arguments[0]);
9230
+ target = { kind: "dynFrom", value: target, type: DYN, loc: locOf(call.arguments[0]), ...(fnName !== null ? { fnName } : {}) };
9231
+ }
9232
+ const descriptorPrimitive = member === "getOwnPropertyDescriptor" && target &&
9233
+ (target.type.kind === "bool" || target.type.kind === "f64" || target.type.kind === "string");
9234
+ if (!target || (target.type.kind !== "dyn" && !isUnitType(target.type) && !descriptorPrimitive))
9235
+ return null;
9236
+ if (target.type.kind !== "dyn")
9237
+ target = { kind: "dynFrom", value: target, type: DYN, loc: locOf(call.arguments[0]) };
9238
+ const key = lowerer.lowerExprExpecting(call.arguments[1], DYN);
9239
+ if (key.type.kind !== "dyn")
9240
+ return null;
9241
+ if (member === "getOwnPropertyDescriptor") {
9242
+ return { kind: "libCall", fn: "dyn.getOwnPropertyDescriptor", args: [target, key], type: DYN, loc: locOf(call) };
9243
+ }
9244
+ const descriptor = lowerer.lowerExprExpecting(call.arguments[2], DYN);
9245
+ if (descriptor.type.kind !== "dyn")
9246
+ return null;
9247
+ return { kind: "libCall", fn: "dyn.defineProperty", args: [target, key, descriptor], type: DYN, loc: locOf(call) };
9248
+ }
8262
9249
  // Object.defineProperties over a CHECKED-DYNAMIC target (test/common's
8263
9250
  // _mustCallInner copying name/length onto the mustCall wrapper): the
8264
- // runtime turns each descriptor's `value` into a plain own property on
8265
- // the dyn node (OBJ members; FUNC nodes carry an own-property table) —
8266
- // flags accepted and ignored, accessors throw loudly (SEMANTICS.md).
9251
+ // runtime turns each descriptor's `value` into an own property on
9252
+ // the dyn node (OBJ members preserve attributes; FUNC nodes carry an
9253
+ // own-property table). Accessors use the target as their receiver.
8267
9254
  // The result is the target, like JS. Typed targets keep the fence:
8268
9255
  // static shapes have no property table to extend.
8269
9256
  if (member === "defineProperties" && call.arguments.length === 2 &&
8270
9257
  !call.arguments.some((a) => ts.isSpreadElement(a))) {
8271
9258
  let target = tryLowerExpression(lowerer, call.arguments[0]);
9259
+ if (target) {
9260
+ const native = lowerClassDataDescriptor(lowerer, call, member, target);
9261
+ if (native)
9262
+ return native;
9263
+ }
8272
9264
  // A FUNCTION-typed target boxes through the dyn boundary: the
8273
9265
  // property table lives on the CLOSURE (shared by every box of this
8274
9266
  // function value), so defining through a fresh box sticks — the
8275
9267
  // wrapper returned later reads the same table.
8276
9268
  if (target && target.type.kind === "func" &&
8277
9269
  canBoxFuncIntoDyn(target.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
9270
+ const fnName = jsFuncNameOf(call.arguments[0]);
9271
+ target = { kind: "dynFrom", value: target, type: DYN, loc: locOf(call.arguments[0]), ...(fnName !== null ? { fnName } : {}) };
9272
+ }
9273
+ if (target && isUnitType(target.type)) {
8278
9274
  target = { kind: "dynFrom", value: target, type: DYN, loc: locOf(call.arguments[0]) };
8279
9275
  }
8280
9276
  if (target?.type.kind === "dyn") {
@@ -8285,12 +9281,39 @@ function lowerObjectStaticCall(lowerer, call, access) {
8285
9281
  }
8286
9282
  return null;
8287
9283
  }
9284
+ if (["preventExtensions", "isExtensible", "seal", "isSealed"].includes(member) &&
9285
+ call.arguments.length === 1 && !ts.isSpreadElement(call.arguments[0])) {
9286
+ const value = lowerer.lowerExpr(call.arguments[0]);
9287
+ if (value.type.kind === "string" || value.type.kind === "f64" ||
9288
+ value.type.kind === "bool" || value.type.kind === "symbol" || isUnitType(value.type)) {
9289
+ if (member === "preventExtensions" || member === "seal")
9290
+ return value;
9291
+ const loc = locOf(call);
9292
+ const answer = { kind: "boolLit", value: member !== "isExtensible", type: BOOL, loc };
9293
+ return isSafeToDiscard(value) ? answer : {
9294
+ kind: "seqExpr", stmts: [{ kind: "exprStmt", expr: value, loc: value.loc }],
9295
+ result: answer, type: BOOL, loc,
9296
+ };
9297
+ }
9298
+ if (value.type.kind === "dyn") {
9299
+ const operation = {
9300
+ preventExtensions: "dyn.preventExtensions", isExtensible: "dyn.isExtensible",
9301
+ seal: "dyn.seal", isSealed: "dyn.isSealed",
9302
+ };
9303
+ const fn = operation[member];
9304
+ return { kind: "libCall", fn, args: [value], type: member.startsWith("is") ? BOOL : DYN, loc: locOf(call) };
9305
+ }
9306
+ }
8288
9307
  // Object.freeze: on a FRESH literal (object or array) the result IS
8289
9308
  // the argument — no alias exists, so the frozen bit is unobservable
8290
9309
  // (writes through the Readonly<T> result are compile errors, and no
8291
9310
  // other reference can write). Primitives pass through per ES2015.
8292
9311
  // Aliased objects keep a fence: a later write through the original
8293
9312
  // reference would need the runtime frozen bit (strict mode throws).
9313
+ if (member === "isFrozen" && call.arguments.length === 1) {
9314
+ const value = lowerer.lowerExprExpecting(call.arguments[0], DYN);
9315
+ return { kind: "libCall", fn: "dyn.isFrozen", args: [value], type: BOOL, loc: locOf(call) };
9316
+ }
8294
9317
  if (member === "freeze") {
8295
9318
  if (call.arguments.length !== 1 || ts.isSpreadElement(call.arguments[0])) {
8296
9319
  lowerer.noLowering(`Object.freeze with ${call.arguments.length} arguments`, call);
@@ -8300,14 +9323,18 @@ function lowerObjectStaticCall(lowerer, call, access) {
8300
9323
  while (ts.isParenthesizedExpression(inner) || ts.isAsExpression(inner))
8301
9324
  inner = inner.expression;
8302
9325
  const value = lowerer.lowerExpr(argNode);
9326
+ if (value.type.kind === "dyn")
9327
+ return { kind: "libCall", fn: "dyn.freeze", args: [value], type: DYN, loc: locOf(call) };
8303
9328
  if (ts.isObjectLiteralExpression(inner) || ts.isArrayLiteralExpression(inner)) {
8304
9329
  return value; // fresh — freeze is identity here, honestly
8305
9330
  }
8306
9331
  if (value.type.kind === "string" || value.type.kind === "f64" ||
8307
- value.type.kind === "bool" || value.type.kind === "symbol" ||
9332
+ value.type.kind === "bool" || value.type.kind === "symbol" || value.type.kind === "bigint" ||
8308
9333
  isUnitType(value.type)) {
8309
9334
  return value; // ES2015: freeze of a primitive is the primitive
8310
9335
  }
9336
+ if (value.type.kind === "union" && lowerer.unions.get(value.type.unionId)?.arms.every((arm) => isUnitType(arm) || arm.kind === "f64" || arm.kind === "bigint" || arm.kind === "bool" || arm.kind === "string" || arm.kind === "symbol"))
9337
+ return value;
8311
9338
  lowerer.noLowering("Object.freeze of a possibly-aliased value", call, "freeze of a FRESH object/array literal (and of primitives) compiles — frozen-ness is unobservable there; an aliased target's later writes would need the runtime frozen bit");
8312
9339
  }
8313
9340
  // `Object.hasOwn(r, k)` over a RECORD receiver: a record's own-key set
@@ -8316,44 +9343,46 @@ function lowerObjectStaticCall(lowerer, call, access) {
8316
9343
  // fields answer by their runtime tag — the explicit-undefined-is-absent
8317
9344
  // stance: an omitted optional field holds the undefined arm and reads
8318
9345
  // as NOT own, exactly Node's absent key (an EXPLICIT `k: undefined`
8319
- // diverges — documented next to the child-env/JSON rule). Tuple,
8320
- // index-signature (overflow membership lives in the runtime map), and
8321
- // accessor-carrying shapes keep the SC2020 fence; non-record receivers
9346
+ // diverges — documented next to the child-env/JSON rule). Tuple
9347
+ // and accessor-carrying shapes keep the SC2020 fence. Index-signature
9348
+ // records additionally probe the overflow map; non-record receivers
8322
9349
  // do too.
8323
9350
  if (member === "hasOwn" && call.arguments.length === 2 && !call.arguments.some((a) => ts.isSpreadElement(a))) {
8324
9351
  const recvNode = call.arguments[0];
8325
9352
  const keyNode = call.arguments[1];
8326
9353
  const probed = tryLowerExpression(lowerer, recvNode);
9354
+ const constructor = probed?.type.kind === "classval" ? lowerer.classes.get(probed.type.className) : undefined;
8327
9355
  // A CHECKED-DYNAMIC receiver (the JS file-scope object-literal
8328
9356
  // identity story): the runtime dyn probe — OBJ member presence, ARR
8329
9357
  // index bounds, Node's ToObject TypeError on nullish.
8330
- if (probed?.type.kind === "dyn") {
9358
+ if (probed?.type.kind === "dyn" || (probed && isDynTypedRefType(probed.type)) ||
9359
+ (probed?.type.kind === "object" && lowerer.errorHierarchyClassOf(probed.type.className)) ||
9360
+ (probed && constructor && (constructor.callableBase || hasRuntimeStatics(constructor))) ||
9361
+ (probed?.type.kind === "func" && lowerer.dynConvertible(probed.type))) {
8331
9362
  const loc = locOf(call);
8332
- const receiver = lowerer.lowerExpr(recvNode);
8333
- let key = lowerer.lowerExpr(keyNode);
8334
- if (key.type.kind === "f64" || key.type.kind === "bool" || key.type.kind === "dyn") {
8335
- key = { kind: "toString", operand: key, type: STRING, loc: locOf(keyNode) };
8336
- }
8337
- if (key.type.kind !== "string")
9363
+ const receiver = lowerer.coerceToExpected(probed, DYN);
9364
+ const rawKey = lowerer.lowerExpr(keyNode);
9365
+ if (rawKey.type.kind === "dyn" || rawKey.type.kind === "symbol" ||
9366
+ rawKey.type.kind === "union" && lowerer.dynConvertible(rawKey.type))
9367
+ return {
9368
+ kind: "libCall", fn: "dyn.hasOwnComputed", args: [receiver, lowerer.coerceToExpected(rawKey, DYN)], type: BOOL, loc,
9369
+ };
9370
+ const key = ownPropertyKey(lowerer, rawKey);
9371
+ if (!key)
8338
9372
  return null;
8339
9373
  return { kind: "libCall", fn: "dyn.hasOwn", args: [receiver, key], type: BOOL, loc };
8340
9374
  }
8341
9375
  if (probed?.type.kind !== "record")
8342
9376
  return null;
8343
9377
  const shape = lowerer.shapes.get(probed.type.shapeId);
8344
- if (!shape || shape.tuple || shape.indexValue || shapeHasAccessorSlots(shape))
9378
+ if (!shape || shape.tuple || shapeHasAccessorSlots(shape))
8345
9379
  return null;
8346
9380
  const loc = locOf(call);
8347
9381
  const receiver = lowerer.lowerExpr(recvNode);
8348
9382
  if (receiver.type.kind !== "record")
8349
9383
  return null; // probe/lower drift: keep the fence
8350
- let key = lowerer.lowerExpr(keyNode);
8351
- // Number/boolean/dyn keys stringify — ToPropertyKey, the keyed-write
8352
- // path's rule; symbol and composite keys keep the fence.
8353
- if (key.type.kind === "f64" || key.type.kind === "bool" || key.type.kind === "dyn") {
8354
- key = { kind: "toString", operand: key, type: STRING, loc: locOf(keyNode) };
8355
- }
8356
- if (key.type.kind !== "string")
9384
+ const key = ownPropertyKey(lowerer, lowerer.lowerExpr(keyNode));
9385
+ if (!key)
8357
9386
  return null;
8358
9387
  const helper = recordHasOwnHelper(lowerer, receiver.type.shapeId, loc);
8359
9388
  return { kind: "call", callee: helper, args: [receiver, key], type: BOOL, loc };
@@ -8415,8 +9444,12 @@ function lowerObjectStaticCall(lowerer, call, access) {
8415
9444
  const isDyn = probed?.type.kind === "dyn";
8416
9445
  // Unit-typed arguments (Object.keys(null)) ride the same runtime
8417
9446
  // walk: it throws Node's catchable TypeError.
8418
- const isUnit = probed !== null && probed !== undefined && isUnitType(probed.type);
8419
- if (isDyn || isUnit) {
9447
+ const isFunction = probed?.type.kind === "func" && lowerer.dynConvertible(probed.type);
9448
+ const isPrimitive = probed !== null && probed !== undefined &&
9449
+ (isUnitType(probed.type) || probed.type.kind === "string" ||
9450
+ probed.type.kind === "f64" || probed.type.kind === "bool");
9451
+ const isJsUnion = probed?.type.kind === "union" && isJsSourceFile(call.getSourceFile()) && lowerer.dynConvertible(probed.type);
9452
+ if (isDyn || isPrimitive || isFunction || isJsUnion || (probed && isDynTypedRefType(probed.type))) {
8420
9453
  const fn = member === "keys" ? "dyn.objKeys" : member === "values" ? "dyn.objValues" : "dyn.objEntries";
8421
9454
  let v = lowerer.lowerExpr(argNode);
8422
9455
  if (v.type.kind !== "dyn")
@@ -8445,6 +9478,19 @@ function lowerObjectStaticCall(lowerer, call, access) {
8445
9478
  if (shapeHasAccessorSlots(shape)) {
8446
9479
  lowerer.unsupported("SC1090", call, `Object.${member} over a shape carrying get/set accessor properties (Node lists the accessor names${member === "keys" ? "" : " and invokes the getters"} — the static key walk cannot; read the properties explicitly)`);
8447
9480
  }
9481
+ // unknown[] uses the checked-dynamic array representation. Enumerate
9482
+ // a live view of the record so values retain their identities and the
9483
+ // result never pretends to be a native vector or an island array.
9484
+ const enumerationType = lowerer.mapTypeOf(lowerer.typeOf(call));
9485
+ if ((member === "values" || member === "entries") &&
9486
+ (enumerationType?.kind === "dyn" || enumerationType === null && isJsSourceFile(call.getSourceFile()))) {
9487
+ let receiver = lowerer.coerceToExpected(lowerer.lowerExpr(argNode), DYN);
9488
+ if (receiver.type.kind !== "dyn")
9489
+ lowerer.badType(argNode, lowerer.typeOf(argNode));
9490
+ if (receiver.kind === "dynFrom" && receiver.value.type.kind === "record")
9491
+ receiver = { ...receiver, liveRef: true };
9492
+ return { kind: "libCall", fn: member === "values" ? "dyn.objValues" : "dyn.objEntries", args: [receiver], type: DYN, loc: locOf(call) };
9493
+ }
8448
9494
  if (shape.indexValue) {
8449
9495
  // Index-signature (overflow-carrying) shapes: the runtime walk —
8450
9496
  // declared fields first, then the overflow in JS own-key order
@@ -8455,7 +9501,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
8455
9501
  const resultT = lowerer.irTypeOf(call);
8456
9502
  if (resultT.kind !== "array")
8457
9503
  lowerer.badType(call, lowerer.typeOf(call)); // defensive
8458
- const receiver = lowerer.lowerExpr(argNode);
9504
+ const receiver = objectEnumerationReceiver(lowerer, lowerer.lowerExpr(argNode), argIr, loc);
8459
9505
  if (member === "keys") {
8460
9506
  // The keys walk is shared with for-in (which iterates exactly the
8461
9507
  // keys Object.keys answers — one construction, one intern key).
@@ -8484,7 +9530,6 @@ function lowerObjectStaticCall(lowerer, call, access) {
8484
9530
  const recT = argIr;
8485
9531
  const ref = { kind: "varRef", localId: "r.0", type: recT, loc };
8486
9532
  const outRef = { kind: "varRef", localId: "out.0", type: resultT, loc };
8487
- lowerer.arrHofHelpers.set(key, helper);
8488
9533
  const fn = {
8489
9534
  name: helper,
8490
9535
  params: [{ localId: "r.0", name: "r", type: recT }],
@@ -8497,7 +9542,8 @@ function lowerObjectStaticCall(lowerer, call, access) {
8497
9542
  loc,
8498
9543
  };
8499
9544
  const finalize = () => {
8500
- const current = lowerer.shapes.get(argIr.shapeId) ?? shape;
9545
+ const latest = lowerer.shapes.get(argIr.shapeId);
9546
+ const current = latest !== undefined ? latest : shape;
8501
9547
  const body = [
8502
9548
  { kind: "varDecl", localId: "out.0", init: { kind: "arrayLit", elems: [], type: resultT, loc }, loc },
8503
9549
  ];
@@ -8512,6 +9558,8 @@ function lowerObjectStaticCall(lowerer, call, access) {
8512
9558
  return null;
8513
9559
  if (typeEquals(vt, valueT))
8514
9560
  return value;
9561
+ if (valueT.kind === "dyn" && lowerer.dynConvertible(vt))
9562
+ return lowerer.coerceToExpected(value, DYN);
8515
9563
  if (valueT.kind === "union" && vt.kind !== "union") {
8516
9564
  const tag = lowerer.armTag(valueT.unionId, vt);
8517
9565
  if (tag >= 0) {
@@ -8531,7 +9579,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
8531
9579
  guardUndefTag = undefTag;
8532
9580
  const arms = lowerer.unions.get(f.type.unionId)?.arms ?? [];
8533
9581
  const others = arms.filter((a) => a.kind !== "undefinedT");
8534
- if (typeEquals(f.type, valueT ?? f.type)) {
9582
+ if (valueT?.kind === "dyn" || typeEquals(f.type, valueT ?? f.type)) {
8535
9583
  // The field union IS the result union (single-field shapes):
8536
9584
  // push the raw box — but then the undefined skip must NOT
8537
9585
  // narrow. Handled below via vt === valueT.
@@ -8555,7 +9603,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
8555
9603
  "cannot re-tag into the result element type — read the fields directly)");
8556
9604
  }
8557
9605
  }
8558
- else if (!typeEquals(f.type, valueT ?? f.type)) {
9606
+ else if (valueT?.kind !== "dyn" && !typeEquals(f.type, valueT ?? f.type)) {
8559
9607
  lowerer.unsupported("SC1090", call, `Object.${member} over '${lowerer.fmt(argIr)}' (field '${f.name}' is a union that cannot ` +
8560
9608
  "re-tag into the result element type — read the fields directly)");
8561
9609
  }
@@ -8595,6 +9643,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
8595
9643
  fn.body = body;
8596
9644
  };
8597
9645
  finalize();
9646
+ lowerer.arrHofHelpers.set(key, helper);
8598
9647
  lowerer.shapeOrderHelperFinalizers.push(finalize);
8599
9648
  lowerer.liftedFns.push(fn);
8600
9649
  }
@@ -8643,6 +9692,15 @@ export function lowerFunction(lowerer, decl) {
8643
9692
  params.push({ localId: argsLocal.id, name: "%arguments", type: DYN });
8644
9693
  ctx.argumentsLocal = argsLocal;
8645
9694
  }
9695
+ if (isJsSourceFile(decl.getSourceFile()) && sig.params.length === 1 &&
9696
+ sig.params[0]?.mode === "dynRest" && bodyReadsArguments(decl)) {
9697
+ const argsLocal = lowerer.declareHiddenLocal("%arguments", DYN);
9698
+ prologue.push({ kind: "varDecl", localId: argsLocal.id, init: {
9699
+ kind: "dynInvoke", recv: varRef(params[0].localId, DYN, locOf(decl)), method: "slice",
9700
+ calleeName: "Array.prototype.slice", args: [], type: DYN, loc: locOf(decl),
9701
+ }, loc: locOf(decl) });
9702
+ ctx.argumentsLocal = argsLocal;
9703
+ }
8646
9704
  const bodyBlock = blockBodyOf(decl);
8647
9705
  if (!bodyBlock) {
8648
9706
  lowerer.unsupported("SC1090", decl, "function declarations whose block body the frontend cannot locate");
@@ -8651,6 +9709,8 @@ export function lowerFunction(lowerer, decl) {
8651
9709
  appendImplicitUndefinedReturn(lowerer, body, bodyReturn, locOf(decl));
8652
9710
  const fn = {
8653
9711
  name: sig.name,
9712
+ sourceName: decl.name?.text ?? "<anonymous>",
9713
+ ...(!sig.isAsync && !sig.generator ? { ownsPrototype: true } : {}),
8654
9714
  params,
8655
9715
  returnType: bodyReturn,
8656
9716
  locals: lowerer.ctx.locals,
@@ -8775,8 +9835,27 @@ function lowerObjectAssignHybrid(lowerer, call) {
8775
9835
  export function lowerRecordFieldCall(lowerer, call, access) {
8776
9836
  if (lowerer.chainBlocked(call))
8777
9837
  return null;
8778
- if (lowerer.mapTypeOf(lowerer.typeOf(access.expression))?.kind !== "record")
8779
- return null;
9838
+ const stored = ts.isIdentifier(access.expression)
9839
+ ? lowerer.peekLocal(access.expression)?.type ?? lowerer.globalOf(access.expression)?.type : undefined;
9840
+ const receiverType = stored?.kind === "record" ? stored : lowerer.mapTypeOf(lowerer.typeOf(access.expression));
9841
+ if (receiverType?.kind !== "record" && receiverType?.kind !== "union")
9842
+ return null;
9843
+ // A union of records can share a closure-valued field. Its normal
9844
+ // property read performs the tag dispatch before arguments evaluate.
9845
+ // Class methods retain their vtable path and must not lose `this`.
9846
+ if (receiverType.kind === "union") {
9847
+ const arms = lowerer.unions.get(receiverType.unionId)?.arms;
9848
+ if (!arms?.every((arm) => arm.kind === "record"))
9849
+ return null;
9850
+ if (!arms.every((arm) => arm.kind === "record" &&
9851
+ lowerer.shapes.get(arm.shapeId)?.fields.some((field) => field.name === access.name.text && field.type.kind === "func")))
9852
+ return null;
9853
+ const callee = lowerer.lowerUnionProperty(access);
9854
+ if (callee?.type.kind !== "func")
9855
+ return null;
9856
+ const args = completeFuncValueArgs(lowerer, call, callee.type, locOf(call));
9857
+ return { kind: "callValue", callee, args, type: callee.type.ret, loc: locOf(call) };
9858
+ }
8780
9859
  const target = lowerer.fieldTarget(access);
8781
9860
  let callee = target ? lowerer.fieldGetExpr(target, locOf(access), access) : null;
8782
9861
  if (!callee)
@@ -8975,7 +10054,7 @@ function nullishValueUnitOf(lowerer, sym) {
8975
10054
  // the no-storage family never claims it.
8976
10055
  if (!decl || !ts.isVariableDeclaration(decl) || !ts.isIdentifier(decl.name) ||
8977
10056
  decl.getSourceFile().isDeclarationFile || decl.initializer === undefined ||
8978
- !ts.isVariableStatement(decl.parent.parent)) {
10057
+ !ts.isVariableStatement(decl.parent?.parent)) {
8979
10058
  return null;
8980
10059
  }
8981
10060
  const unit = nullishExprUnitOf(lowerer, decl.initializer);
@@ -9161,7 +10240,7 @@ export function deadUnmappableBinding(lowerer, sym, decl) {
9161
10240
  // lowerVarDeclList's contract requires a lowered statement for it, so
9162
10241
  // the no-storage family never claims it (catch bindings sit outside a
9163
10242
  // variable statement too and stay out the same way).
9164
- if (!ts.isVariableStatement(decl.parent.parent))
10243
+ if (!ts.isVariableStatement(decl.parent?.parent))
9165
10244
  return false;
9166
10245
  const sf = decl.getSourceFile();
9167
10246
  if (sf.isDeclarationFile || isJsSourceFile(sf))
@@ -9339,11 +10418,11 @@ export function bindingGenericFnInfoOf(lowerer, decl, fnNode) {
9339
10418
  lowerer.unsupported("SC1031", param);
9340
10419
  }
9341
10420
  }
9342
- const stmt = decl.parent.parent; // declarator → list → statement (nsPathPrefix wants the statement)
10421
+ const stmt = decl.parent?.parent; // declarator → list → statement (nsPathPrefix wants the statement)
9343
10422
  const info = {
9344
10423
  decl: fnNode,
9345
10424
  baseName: name,
9346
- qualifiedName: lowerer.qualify(decl.getSourceFile(), nsPathPrefix(stmt, decl) + name),
10425
+ qualifiedName: lowerer.qualify(decl.getSourceFile(), nsPathPrefix(stmt ?? decl, decl) + name),
9347
10426
  typeParams,
9348
10427
  instances: new Map(),
9349
10428
  };
@@ -9475,6 +10554,88 @@ function arrowSignatureOf(lowerer, node) {
9475
10554
  const declaration = lowerer.checker.signatureDeclaration(signatures[0]);
9476
10555
  return declaration !== undefined && ts.isArrowFunction(declaration) ? signatures[0] : null;
9477
10556
  }
10557
+ /** An inline arrow has lexical `this` and no observable own properties
10558
+ * before binding. With no preset arguments, a fresh forwarding closure
10559
+ * preserves its completed ABI, defaults and captured environment. Keep
10560
+ * other receivers and rest/preset-argument forms on the named fence. */
10561
+ function lowerInlineArrowBind(lowerer, call, access) {
10562
+ if (access.name.text !== "bind" || call.arguments.length > 1 || call.arguments.some(ts.isSpreadElement))
10563
+ return null;
10564
+ let arrow = access.expression;
10565
+ while (ts.isParenthesizedExpression(arrow))
10566
+ arrow = arrow.expression;
10567
+ if (!ts.isArrowFunction(arrow))
10568
+ return null;
10569
+ const callee = lowerer.lowerExpr(access.expression);
10570
+ if (callee.type.kind !== "func" || callee.type.rest ||
10571
+ !canBoxFuncIntoDyn(callee.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id)))
10572
+ return null;
10573
+ const type = callee.type;
10574
+ const loc = locOf(call);
10575
+ const firstDefault = arrow.parameters.findIndex((p) => p.initializer !== undefined);
10576
+ const length = firstDefault < 0 ? arrow.parameters.length : firstDefault;
10577
+ const key = `arrow.bind:${typeKey(type)}:${length}`;
10578
+ const existing = lowerer.arrHofHelpers.get(key);
10579
+ const name = existing ?? `%arrow.bind.${lowerer.arrHofHelpers.size}`;
10580
+ if (!existing) {
10581
+ lowerer.arrHofHelpers.set(key, name);
10582
+ lowerer.freshClosureAdapters.add(name);
10583
+ const impl = `${name}.impl`;
10584
+ const captured = { id: "f.0", name: "f", type, mutable: false, boxed: true };
10585
+ const params = type.params.map((type, i) => ({ localId: `p.${i}`, name: `p${i}`, type }));
10586
+ const invoked = {
10587
+ kind: "callValue",
10588
+ callee: { kind: "varRef", localId: captured.id, type, loc },
10589
+ args: params.map((p) => ({ kind: "varRef", localId: p.localId, type: p.type, loc })),
10590
+ type: type.ret,
10591
+ loc,
10592
+ };
10593
+ lowerer.liftedFns.push({
10594
+ name: impl,
10595
+ params,
10596
+ returnType: type.ret,
10597
+ captures: [{ localId: captured.id, name: captured.name, type }],
10598
+ locals: [captured, ...params.map((p) => ({ id: p.localId, name: p.name, type: p.type, mutable: false }))],
10599
+ body: [type.ret.kind === "void" ? { kind: "exprStmt", expr: invoked, loc } : { kind: "return", value: invoked, loc }],
10600
+ loc,
10601
+ });
10602
+ const bound = { kind: "varRef", localId: "bound.0", type, loc };
10603
+ const str = (value) => ({ kind: "strLit", value, type: STRING, loc });
10604
+ const descriptor = (value) => ({
10605
+ kind: "dynObjLit", fields: [{ key: str("value"), value: { kind: "dynFrom", value, type: DYN, loc } }], type: DYN, loc,
10606
+ });
10607
+ lowerer.liftedFns.push({
10608
+ name,
10609
+ params: [{ localId: captured.id, name: captured.name, type }],
10610
+ returnType: type,
10611
+ locals: [captured, { id: "bound.0", name: "bound", type, mutable: false }],
10612
+ body: [
10613
+ { kind: "varDecl", localId: "bound.0", init: { kind: "closure", fnName: impl, captures: [captured.id], type, loc }, loc },
10614
+ // Store metadata on the closure so aliases and repeated dyn boxes
10615
+ // observe the bound name and source arity, including defaults.
10616
+ { kind: "exprStmt", expr: {
10617
+ kind: "libCall", fn: "dyn.defineProps", args: [
10618
+ { kind: "dynFrom", value: bound, type: DYN, loc },
10619
+ { kind: "dynObjLit", fields: [
10620
+ { key: str("name"), value: descriptor(str("bound ")) },
10621
+ { key: str("length"), value: descriptor({ kind: "numLit", value: length, type: F64, loc }) },
10622
+ ], type: DYN, loc },
10623
+ ], type: DYN, loc,
10624
+ }, loc },
10625
+ { kind: "return", value: bound, loc },
10626
+ ],
10627
+ loc,
10628
+ });
10629
+ }
10630
+ const saved = lowerer.declareHiddenLocal("%bindFn", type);
10631
+ const stmts = [{ kind: "varDecl", localId: saved.id, init: callee, loc }];
10632
+ // The receiver is ignored by the arrow, but its effects and throws
10633
+ // happen after creating the arrow and before returning the bound value.
10634
+ if (call.arguments[0])
10635
+ stmts.push(lowerer.lowerExprStatement(call.arguments[0]));
10636
+ const result = { kind: "call", callee: name, args: [{ kind: "varRef", localId: saved.id, type, loc }], type, loc };
10637
+ return { kind: "seqExpr", stmts, result, type, loc };
10638
+ }
9478
10639
  /** `arrow.apply(thisArg, dynArgs)` for a fixed-arity compiled arrow. Arrows
9479
10640
  * ignore `thisArg` and surplus arguments by language definition; declared
9480
10641
  * parameters validate from the dynamic array in order. */
@@ -9553,7 +10714,6 @@ function lowerObjLitGenericMethodCall(lowerer, call, access) {
9553
10714
  thisT.kind !== "dyn" &&
9554
10715
  thisT.kind !== "jsval" &&
9555
10716
  (!thisArg || ts.isIdentifier(thisArg) || ts.isLiteralExpression(thisArg) ||
9556
- thisArg.kind === ts.SyntaxKind.UndefinedKeyword ||
9557
10717
  thisArg.kind === ts.SyntaxKind.NullKeyword ||
9558
10718
  isUnitType(thisT));
9559
10719
  if (provablyNot) {
@@ -9564,6 +10724,14 @@ function lowerObjLitGenericMethodCall(lowerer, call, access) {
9564
10724
  const propSym = lowerer.checker.getPropertyOfType(recvT, name);
9565
10725
  if (!propSym)
9566
10726
  return null;
10727
+ const propertyDecl = lowerer.checker.valueDeclarationOf(propSym);
10728
+ if (propertyDecl && ts.isShorthandPropertyAssignment(propertyDecl) && ts.isIdentifier(propertyDecl.name) && ts.isObjectLiteralExpression(propertyDecl.parent)) {
10729
+ requireObjLitGenericReceiver(lowerer, call, access.expression, propertyDecl.parent, name);
10730
+ const targetSymbol = lowerer.checker.getShorthandAssignmentValueSymbol(propertyDecl);
10731
+ const target = targetSymbol ? lowerer.genericFnsBySymbol.get((targetSymbol.flags & ts.SymbolFlags.Alias ? lowerer.checker.getAliasedSymbol(targetSymbol) : targetSymbol)) : undefined;
10732
+ if (target)
10733
+ return lowerer.lowerGenericCall(call, target);
10734
+ }
9567
10735
  if (!isGenericCallableMemberType(lowerer.checker.getTypeOfSymbol(propSym), lowerer.checker))
9568
10736
  return null;
9569
10737
  // CLASS members belong to the class path (lowerClassGenericMethodCall
@@ -9592,19 +10760,25 @@ function lowerObjLitGenericMethodCall(lowerer, call, access) {
9592
10760
  }
9593
10761
  const found = objLitGenericFnNodeOf(lowerer, propSym);
9594
10762
  if (!found) {
10763
+ const arrowBind = lowerInlineArrowBind(lowerer, call, access);
10764
+ if (arrowBind !== null)
10765
+ return arrowBind;
9595
10766
  const arrowApply = lowerArrowFunctionApply(lowerer, call, access);
9596
10767
  if (arrowApply !== null)
9597
10768
  return arrowApply;
9598
- // Function.prototype.apply/call/bind spelled through a FUNCTION
9599
- // receiver: compiled functions are direct calls with no runtime
9600
- // `this`/arguments object to re-route — name the working spelling
9601
- // instead of a class-receiver hint (or an SC2020 recitation) no
9602
- // function value can follow. Before the stdlib decline: these ARE
9603
- // stdlib members (CallableFunction), but the pointed message is
9604
- // the honest one.
10769
+ // Convertible native callables use the checked invocation boundary
10770
+ // for Function.prototype methods, including their call-time receiver.
9605
10771
  if ((name === "apply" || name === "call" || name === "bind") &&
9606
10772
  lowerer.checker.getCallSignatures(recvT).length > 0) {
9607
- lowerer.unsupported("SC1090", call, `Function.prototype.${name} on a compiled function value (compiled calls are direct — no runtime 'this' or arguments object exists to re-route; spell the call directly: '${access.expression.getText()}(...)')`);
10773
+ const value = tryLowerExpression(lowerer, access.expression);
10774
+ if (value?.type.kind === "func" && lowerer.dynConvertible(value.type) && !call.arguments.some(ts.isSpreadElement)) {
10775
+ const loc = locOf(call);
10776
+ return {
10777
+ kind: "dynInvoke", recv: { kind: "dynFrom", value, type: DYN, loc }, method: name,
10778
+ calleeName: access.getText(), args: call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc,
10779
+ };
10780
+ }
10781
+ lowerer.unsupported("SC1090", call, `Function.prototype.${name} on a function whose signature cannot cross the checked-value boundary (call '${access.expression.getText()}(...)' directly)`);
9608
10782
  }
9609
10783
  // STANDARD-LIBRARY generic members (Promise.then, Object.
9610
10784
  // defineProperty, Array-augmentation methods) are the lib fence's
@@ -9641,12 +10815,27 @@ function lowerObjLitGenericMethodCall(lowerer, call, access) {
9641
10815
  export function lowerObjectMethodCall(lowerer, call, access) {
9642
10816
  if (lowerer.chainBlocked(access, call))
9643
10817
  return null;
9644
- const mappedReceiver = lowerer.mapTypeOf(lowerer.typeOf(access.expression));
10818
+ let mappedReceiver = lowerer.mapTypeOf(lowerer.typeOf(access.expression));
10819
+ // A specialized JS parameter can expose a native field whose checker
10820
+ // type still belongs to the unspecialized body (plane.normal.dot()).
10821
+ // Use the lowered receiver's representation and retain its evaluation.
10822
+ const probe = mappedReceiver?.kind !== "object" && (lowerer.implicitParamTypes !== null || ts.isNewExpression(access.expression) ||
10823
+ isJsSourceFile(call.getSourceFile()) && ts.isCallExpression(access.expression))
10824
+ ? tryLowerExpression(lowerer, access.expression) : null;
10825
+ const specializedReceiver = probe?.type.kind === "object" ? probe : null;
10826
+ if (specializedReceiver)
10827
+ mappedReceiver = specializedReceiver.type;
9645
10828
  if (mappedReceiver?.kind === "union") {
9646
10829
  const dispatched = lowerUnionObjectMethodCall(lowerer, call, access, mappedReceiver) ??
9647
10830
  lowerUnionObjectDynFieldCall(lowerer, call, access, mappedReceiver);
9648
10831
  if (dispatched)
9649
10832
  return dispatched;
10833
+ const arms = lowerer.unions.get(mappedReceiver.unionId)?.arms;
10834
+ if (isJsSourceFile(call.getSourceFile()) && arms?.every((arm) => arm.kind === "object" &&
10835
+ !lowerer.classes.get(arm.className)?.def.runtime) && lowerer.dynConvertible(mappedReceiver)) {
10836
+ const receiver = lowerer.coerceInto(access.expression, lowerer.lowerExpr(access.expression), DYN);
10837
+ return lowerDynDispatchMethodCall(lowerer, call, access, receiver, false);
10838
+ }
9650
10839
  }
9651
10840
  const receiverIr = mappedReceiver?.kind === "object"
9652
10841
  ? mappedReceiver
@@ -9654,15 +10843,16 @@ export function lowerObjectMethodCall(lowerer, call, access) {
9654
10843
  ? (() => {
9655
10844
  const arms = lowerer.unions.get(mappedReceiver.unionId)?.arms ?? [];
9656
10845
  const objects = arms.filter((arm) => arm.kind === "object");
9657
- return objects.length === 1 && arms.every((arm) => arm.kind === "object" || isUnitType(arm))
9658
- ? objects[0]
10846
+ const object = objects[0];
10847
+ return objects.length === 1 && object?.kind === "object" && arms.every((arm) => arm.kind === "object" || isUnitType(arm))
10848
+ ? object
9659
10849
  : null;
9660
10850
  })()
9661
10851
  : null;
9662
10852
  if (receiverIr === null)
9663
10853
  return null;
9664
10854
  const lowerReceiver = () => {
9665
- const receiver = lowerer.lowerExpr(access.expression);
10855
+ const receiver = specializedReceiver ?? lowerer.lowerExpr(access.expression);
9666
10856
  const optional = lowerer.runtimeOptionalPropertyReceiver(access.expression, receiver, receiverIr, access.name.text);
9667
10857
  if (optional !== null)
9668
10858
  return optional;
@@ -9671,7 +10861,7 @@ export function lowerObjectMethodCall(lowerer, call, access) {
9671
10861
  if (helper !== null)
9672
10862
  return { kind: "call", callee: helper, args: [receiver], type: receiverIr, loc: locOf(access.expression) };
9673
10863
  }
9674
- return receiver;
10864
+ return receiver.type.kind === "dyn" ? lowerer.coerceInto(access.expression, receiver, receiverIr) : receiver;
9675
10865
  };
9676
10866
  const info = lowerer.classes.get(receiverIr.className);
9677
10867
  if (!info)
@@ -9698,7 +10888,7 @@ export function lowerObjectMethodCall(lowerer, call, access) {
9698
10888
  if (info && !found) {
9699
10889
  const gfound = findGenericMethodOn(lowerer, info, access.name.text);
9700
10890
  if (gfound)
9701
- return lowerClassGenericMethodCall(lowerer, call, access, info, gfound);
10891
+ return lowerClassGenericMethodCall(lowerer, call, access, info, gfound, lowerReceiver());
9702
10892
  }
9703
10893
  // A FUNC-, nullable-FUNC-, or DYN-typed FIELD in call position:
9704
10894
  // `this.cb()` — the ctor-assigned callback field (countdown.js's
@@ -9714,13 +10904,22 @@ export function lowerObjectMethodCall(lowerer, call, access) {
9714
10904
  ? (() => {
9715
10905
  const arms = lowerer.unions.get(fieldType.unionId)?.arms ?? [];
9716
10906
  const funcs = arms.filter((arm) => arm.kind === "func");
9717
- return funcs.length === 1 && arms.every((arm) => arm.kind === "func" || isUnitType(arm))
9718
- ? funcs[0]
10907
+ const func = funcs[0];
10908
+ return funcs.length === 1 && func?.kind === "func" && arms.every((arm) => arm.kind === "func" || isUnitType(arm))
10909
+ ? func
9719
10910
  : null;
9720
10911
  })()
9721
10912
  : null;
9722
10913
  if (fieldType && (callableType !== null || fieldType.kind === "dyn")) {
9723
10914
  const target = lowerer.fieldTarget(access);
10915
+ if (!target)
10916
+ return null;
10917
+ const loc = locOf(call);
10918
+ const receiverLocal = lowerer.declareHiddenLocal("%callReceiver", target.obj.type);
10919
+ const init = { kind: "varDecl", localId: receiverLocal.id, init: target.obj, loc };
10920
+ target.obj = { kind: "varRef", localId: receiverLocal.id, type: receiverLocal.type, loc };
10921
+ const receiver = lowerer.coerceToExpected(target.obj, DYN);
10922
+ const finish = (result) => ({ kind: "seqExpr", stmts: [init], result, type: result.type, loc });
9724
10923
  let callee = target ? lowerer.fieldGetExpr(target, locOf(access), access) : null;
9725
10924
  if (callee?.type.kind === "union" && callableType !== null) {
9726
10925
  const helper = lowerer.narrowedArmHelper(callee.type.unionId, callableType, locOf(access));
@@ -9729,34 +10928,65 @@ export function lowerObjectMethodCall(lowerer, call, access) {
9729
10928
  }
9730
10929
  }
9731
10930
  if (callee?.type.kind === "func") {
10931
+ if ((callee.type.rest === true && callee.type.restAbi === undefined || call.arguments.length > callee.type.params.length) &&
10932
+ isJsSourceFile(call.getSourceFile()) && lowerer.dynConvertible(callee.type)) {
10933
+ const boxed = { kind: "dynFrom", value: callee, type: DYN, loc };
10934
+ const spread = lowerSpreadArgsCall(lowerer, call, boxed, loc);
10935
+ if (spread?.kind === "dynCall")
10936
+ return finish({ ...spread, receiver });
10937
+ const args = call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN));
10938
+ return finish({ kind: "dynCall", callee: boxed, receiver, calleeName: access.getText(), args, type: DYN, loc });
10939
+ }
9732
10940
  const args = completeFuncValueArgs(lowerer, call, callee.type, locOf(call));
9733
- return { kind: "callValue", callee, args, type: callee.type.ret, loc: locOf(call) };
10941
+ return finish({ kind: "callValue", callee, receiver, args, type: callee.type.ret, loc });
9734
10942
  }
9735
10943
  if (callee?.type.kind === "dyn") {
9736
10944
  if (call.arguments.some((a) => ts.isSpreadElement(a))) {
9737
10945
  lowerer.unsupported("SC1090", call, "spread arguments in calls through 'unknown' values");
9738
10946
  }
9739
10947
  const args = call.arguments.map((a) => lowerer.lowerExprExpecting(a, DYN));
9740
- return { kind: "dynCall", callee, calleeName: access.getText(), args, type: DYN, loc: locOf(call) };
10948
+ return finish({ kind: "dynCall", callee, receiver, calleeName: access.getText(), args, type: DYN, loc });
9741
10949
  }
9742
10950
  }
10951
+ if (!fieldType && isJsSourceFile(call.getSourceFile()) && !info.def.runtime && !info.builtinError && !info.builtinEmitter && !info.builtinStream) {
10952
+ const loc = locOf(call);
10953
+ const value = lowerReceiver();
10954
+ const local = lowerer.declareHiddenLocal("%callReceiver", value.type);
10955
+ const reference = { kind: "varRef", localId: local.id, type: value.type, loc };
10956
+ const receiver = lowerer.coerceToExpected(reference, DYN);
10957
+ const callee = { kind: "dynKeyGet", value: receiver,
10958
+ key: { kind: "strLit", value: access.name.text, type: STRING, loc }, type: DYN, loc };
10959
+ const spread = call.arguments.some(ts.isSpreadElement) ? lowerSpreadArgsCall(lowerer, call, callee, loc) : null;
10960
+ if (spread && spread.kind !== "dynCall")
10961
+ lowerer.unsupported("SC1090", call, "native property call spread arguments");
10962
+ const result = spread !== null ? { ...spread, receiver } : { kind: "dynCall", callee, receiver,
10963
+ calleeName: access.getText(), args: call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
10964
+ return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id, init: value, loc }], result, type: DYN, loc };
10965
+ }
9743
10966
  return null;
9744
10967
  }
9745
10968
  if (!info || !found)
9746
10969
  return null;
9747
10970
  const method = access.name.text;
9748
- if (found.declarer.builtinError) {
9749
- // The one builtin method: Error.prototype.toString, a runtime
9750
- // implementation called directly (overriding it is fenced, so no
9751
- // dispatch can ever be needed). Receiver BORROWED by the libCall.
10971
+ if (isClassCallback(lowerer, info, method)) {
10972
+ const loc = locOf(call);
9752
10973
  const receiver = lowerReceiver();
9753
- return {
9754
- kind: "libCall",
9755
- fn: "error.toString",
9756
- args: [lowerer.upcastTo(receiver, found.declarer.def.name)],
9757
- type: STRING,
9758
- loc: locOf(call),
9759
- };
10974
+ const local = lowerer.declareHiddenLocal("%callbackReceiver", receiver.type);
10975
+ const value = { kind: "varRef", localId: local.id, type: receiver.type, loc };
10976
+ const args = lowerer.completeArgs(call.arguments, found.sig.params, loc, call);
10977
+ const virtual = lowerer.overrideBelow(info, method);
10978
+ if (virtual)
10979
+ lowerer.noteVirtualEdge(info, method);
10980
+ else
10981
+ lowerer.noteEdge(`%${found.declarer.def.name}.${method}`);
10982
+ const fallback = virtual
10983
+ ? { kind: "virtualCall", className: info.def.name, method, args: [lowerer.upcastTo(value, info.def.name), ...args], type: found.sig.ret, loc }
10984
+ : { kind: "call", callee: `%${found.declarer.def.name}.${method}`, args: [lowerer.upcastTo(value, found.declarer.def.name), ...args], type: found.sig.ret, loc };
10985
+ const result = classCallbackCall(lowerer, value, method, call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), fallback, loc);
10986
+ return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id, init: receiver, loc }], result, type: result.type, loc };
10987
+ }
10988
+ if (found.declarer.builtinError) {
10989
+ return errorToStringCall(lowerer, lowerReceiver());
9760
10990
  }
9761
10991
  // An ABSTRACT nearest declaration with no concrete override below the
9762
10992
  // static class: no implementation exists for a direct call to target.
@@ -9815,6 +11045,22 @@ function lowerUnionObjectMethodCall(lowerer, call, access, receiverT) {
9815
11045
  plans.push({ arm, info, found });
9816
11046
  }
9817
11047
  const shapes = plans[0].found.sig.params;
11048
+ if (plans.some((plan) => isClassCallback(lowerer, plan.info, method))) {
11049
+ const loc = locOf(call);
11050
+ const local = lowerer.declareHiddenLocal("%unionMethodReceiver", DYN);
11051
+ const receiver = varRef(local.id, DYN, loc);
11052
+ const callee = { kind: "dynKeyGet", value: receiver,
11053
+ key: { kind: "strLit", value: method, type: STRING, loc }, type: DYN, loc };
11054
+ const spread = call.arguments.some(ts.isSpreadElement) ? lowerSpreadArgsCall(lowerer, call, callee, loc) : null;
11055
+ if (spread && spread.kind !== "dynCall")
11056
+ lowerer.unsupported("SC1090", call, "union method spread arguments");
11057
+ const value = spread !== null ? { ...spread, receiver } : { kind: "dynCall", callee, receiver,
11058
+ calleeName: access.getText(), args: call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
11059
+ const resultT = lowerer.mapTypeOf(lowerer.typeOf(call));
11060
+ const result = resultT && !isUnitType(resultT) ? lowerer.coerceToExpected(value, resultT) : value;
11061
+ return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id,
11062
+ init: lowerer.coerceInto(access.expression, lowerer.lowerExpr(access.expression), DYN), loc }], result, type: result.type, loc };
11063
+ }
9818
11064
  if (!plans.every((plan) => paramAbisEqual(shapes, plan.found.sig.params)))
9819
11065
  return null;
9820
11066
  const resultT = lowerer.mapTypeOf(lowerer.typeOf(call));
@@ -9829,7 +11075,10 @@ function lowerUnionObjectMethodCall(lowerer, call, access, receiverT) {
9829
11075
  function paramAbisEqual(left, right) {
9830
11076
  return left.length === right.length && left.every((shape, i) => {
9831
11077
  const other = right[i];
9832
- return other !== undefined && shape.mode === other.mode && typeEquals(shape.type, other.type);
11078
+ return other !== undefined && typeEquals(shape.type, other.type) &&
11079
+ (shape.mode === other.mode || shape.type.kind === "dyn" &&
11080
+ (shape.mode === "required" || shape.mode === "omittable") &&
11081
+ (other.mode === "required" || other.mode === "omittable"));
9833
11082
  });
9834
11083
  }
9835
11084
  /** The JS-class sibling of union method dispatch: every arm stores the
@@ -9854,6 +11103,8 @@ function lowerUnionObjectDynFieldCall(lowerer, call, access, receiverT) {
9854
11103
  const loc = locOf(call);
9855
11104
  const receiver = lowerer.coerceInto(access.expression, lowerer.lowerExpr(access.expression), receiverT);
9856
11105
  const key = `${receiverT.unionId}:dyn-field:${field}`;
11106
+ const receiverLocal = lowerer.declareHiddenLocal("%unionCallReceiver", receiverT);
11107
+ const receiverRef = varRef(receiverLocal.id, receiverT, loc);
9857
11108
  let helper = lowerer.unionCallHelpers.get(key);
9858
11109
  if (!helper) {
9859
11110
  helper = `%union.call.${lowerer.unionCallHelpers.size}`;
@@ -9906,9 +11157,12 @@ function lowerUnionObjectDynFieldCall(lowerer, call, access, receiverT) {
9906
11157
  const locals = params.map((param) => ({ id: param.localId, name: param.name, type: param.type, mutable: false }));
9907
11158
  lowerer.liftedFns.push({ name: helper, params, returnType: DYN, locals, body, loc });
9908
11159
  }
9909
- const callee = { kind: "call", callee: helper, args: [receiver], type: DYN, loc };
11160
+ const callee = { kind: "call", callee: helper, args: [receiverRef], type: DYN, loc };
9910
11161
  const args = call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN));
9911
- return { kind: "dynCall", callee, calleeName: access.getText(), args, type: DYN, loc };
11162
+ return {
11163
+ kind: "seqExpr", stmts: [{ kind: "varDecl", localId: receiverLocal.id, init: receiver, loc }],
11164
+ result: { kind: "dynCall", callee, receiver: lowerer.coerceToExpected(receiverRef, DYN), calleeName: access.getText(), args, type: DYN, loc }, type: DYN, loc,
11165
+ };
9912
11166
  }
9913
11167
  function unionObjectMethodHelper(lowerer, sourceCall, receiverT, method, plans, shapes, resultT, loc) {
9914
11168
  const key = `${receiverT.unionId}:${method}:${shapes.map((shape) => `${shape.mode}:${typeKey(shape.type)}`).join(",")}:${typeKey(resultT)}`;
@@ -9930,13 +11184,7 @@ function unionObjectMethodHelper(lowerer, sourceCall, receiverT, method, plans,
9930
11184
  };
9931
11185
  let invoke;
9932
11186
  if (plan.found.declarer.builtinError) {
9933
- invoke = {
9934
- kind: "libCall",
9935
- fn: "error.toString",
9936
- args: [lowerer.upcastTo(concrete, plan.found.declarer.def.name)],
9937
- type: STRING,
9938
- loc,
9939
- };
11187
+ invoke = errorToStringCall(lowerer, concrete);
9940
11188
  }
9941
11189
  else if (lowerer.overrideBelow(plan.info, method)) {
9942
11190
  lowerer.noteVirtualEdge(plan.info, method);