@scriptc/compiler 0.2.6 → 0.2.7

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 (368) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +5 -18
  2. package/dist/backend/cycle-analysis.d.ts +21 -9
  3. package/dist/backend/cycle-analysis.js +139 -67
  4. package/dist/backend/cycle-analysis.js.map +1 -1
  5. package/dist/backend/cycle-analysis.test.js +283 -3
  6. package/dist/backend/cycle-analysis.test.js.map +1 -1
  7. package/dist/backend/cycle-mutability.d.ts +39 -0
  8. package/dist/backend/cycle-mutability.js +205 -0
  9. package/dist/backend/cycle-mutability.js.map +1 -0
  10. package/dist/backend/link-plan-core.d.ts +2 -1
  11. package/dist/backend/link-plan-core.js +15 -3
  12. package/dist/backend/link-plan-core.js.map +1 -1
  13. package/dist/backend/link-plan.d.ts +2 -1
  14. package/dist/backend/link-plan.js.map +1 -1
  15. package/dist/backend/llvm/alloc.d.ts +40 -0
  16. package/dist/backend/llvm/alloc.js +205 -0
  17. package/dist/backend/llvm/alloc.js.map +1 -0
  18. package/dist/backend/llvm/alloc.test.d.ts +1 -0
  19. package/dist/backend/llvm/alloc.test.js +102 -0
  20. package/dist/backend/llvm/alloc.test.js.map +1 -0
  21. package/dist/backend/llvm/call-lifetimes.d.ts +15 -3
  22. package/dist/backend/llvm/call-lifetimes.js +42 -18
  23. package/dist/backend/llvm/call-lifetimes.js.map +1 -1
  24. package/dist/backend/llvm/call-lifetimes.test.js +170 -0
  25. package/dist/backend/llvm/call-lifetimes.test.js.map +1 -1
  26. package/dist/backend/llvm/classes.d.ts +4 -1
  27. package/dist/backend/llvm/classes.js +35 -32
  28. package/dist/backend/llvm/classes.js.map +1 -1
  29. package/dist/backend/llvm/classes.test.js +36 -3
  30. package/dist/backend/llvm/classes.test.js.map +1 -1
  31. package/dist/backend/llvm/common.d.ts +13 -0
  32. package/dist/backend/llvm/common.js +30 -0
  33. package/dist/backend/llvm/common.js.map +1 -1
  34. package/dist/backend/llvm/constant-callbacks.d.ts +19 -3
  35. package/dist/backend/llvm/constant-callbacks.js +289 -52
  36. package/dist/backend/llvm/constant-callbacks.js.map +1 -1
  37. package/dist/backend/llvm/constant-callbacks.test.js +140 -3
  38. package/dist/backend/llvm/constant-callbacks.test.js.map +1 -1
  39. package/dist/backend/llvm/dense-array-access.d.ts +29 -0
  40. package/dist/backend/llvm/dense-array-access.js +335 -0
  41. package/dist/backend/llvm/dense-array-access.js.map +1 -0
  42. package/dist/backend/llvm/dense-array-access.test.d.ts +1 -0
  43. package/dist/backend/llvm/dense-array-access.test.js +149 -0
  44. package/dist/backend/llvm/dense-array-access.test.js.map +1 -0
  45. package/dist/backend/llvm/dyn.d.ts +34 -0
  46. package/dist/backend/llvm/dyn.js +189 -1
  47. package/dist/backend/llvm/dyn.js.map +1 -1
  48. package/dist/backend/llvm/emitter.d.ts +124 -4
  49. package/dist/backend/llvm/emitter.js +623 -105
  50. package/dist/backend/llvm/emitter.js.map +1 -1
  51. package/dist/backend/llvm/emitter.test.js +68 -6
  52. package/dist/backend/llvm/emitter.test.js.map +1 -1
  53. package/dist/backend/llvm/expr-async.js +58 -4
  54. package/dist/backend/llvm/expr-async.js.map +1 -1
  55. package/dist/backend/llvm/expr-async.test.d.ts +1 -0
  56. package/dist/backend/llvm/expr-async.test.js +62 -0
  57. package/dist/backend/llvm/expr-async.test.js.map +1 -0
  58. package/dist/backend/llvm/expr-calls.js +64 -6
  59. package/dist/backend/llvm/expr-calls.js.map +1 -1
  60. package/dist/backend/llvm/expr-containers.js +16 -5
  61. package/dist/backend/llvm/expr-containers.js.map +1 -1
  62. package/dist/backend/llvm/expr-control.js +92 -2
  63. package/dist/backend/llvm/expr-control.js.map +1 -1
  64. package/dist/backend/llvm/expr-dispatch.js +2 -0
  65. package/dist/backend/llvm/expr-dispatch.js.map +1 -1
  66. package/dist/backend/llvm/expr-dynamic.js +174 -25
  67. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  68. package/dist/backend/llvm/expr-primitives.d.ts +1 -1
  69. package/dist/backend/llvm/expr-primitives.js +52 -24
  70. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  71. package/dist/backend/llvm/expr-primitives.test.js +1 -1
  72. package/dist/backend/llvm/expr-records.js +3 -3
  73. package/dist/backend/llvm/expr-records.js.map +1 -1
  74. package/dist/backend/llvm/expr-stream-bridges.js +59 -2
  75. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  76. package/dist/backend/llvm/expr-stream-bridges.test.js +1 -1
  77. package/dist/backend/llvm/integer-remainder.d.ts +11 -0
  78. package/dist/backend/llvm/integer-remainder.js +91 -0
  79. package/dist/backend/llvm/integer-remainder.js.map +1 -1
  80. package/dist/backend/llvm/layouts.d.ts +2 -1
  81. package/dist/backend/llvm/layouts.js +3 -2
  82. package/dist/backend/llvm/layouts.js.map +1 -1
  83. package/dist/backend/llvm/lazy-captures.d.ts +16 -0
  84. package/dist/backend/llvm/lazy-captures.js +96 -0
  85. package/dist/backend/llvm/lazy-captures.js.map +1 -0
  86. package/dist/backend/llvm/lazy-captures.test.d.ts +1 -0
  87. package/dist/backend/llvm/lazy-captures.test.js +78 -0
  88. package/dist/backend/llvm/lazy-captures.test.js.map +1 -0
  89. package/dist/backend/llvm/lib-filesystem.js +3 -4
  90. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  91. package/dist/backend/llvm/local-array-reads.d.ts +5 -1
  92. package/dist/backend/llvm/local-array-reads.js +78 -17
  93. package/dist/backend/llvm/local-array-reads.js.map +1 -1
  94. package/dist/backend/llvm/local-array-reads.test.js +78 -1
  95. package/dist/backend/llvm/local-array-reads.test.js.map +1 -1
  96. package/dist/backend/llvm/local-union-storage.d.ts +5 -1
  97. package/dist/backend/llvm/local-union-storage.js +48 -6
  98. package/dist/backend/llvm/local-union-storage.js.map +1 -1
  99. package/dist/backend/llvm/local-union-storage.test.js +91 -4
  100. package/dist/backend/llvm/local-union-storage.test.js.map +1 -1
  101. package/dist/backend/llvm/map-read-lifetimes.test.js +1 -1
  102. package/dist/backend/llvm/nullable-fields.d.ts +28 -0
  103. package/dist/backend/llvm/nullable-fields.js +45 -0
  104. package/dist/backend/llvm/nullable-fields.js.map +1 -0
  105. package/dist/backend/llvm/nullable-fields.test.d.ts +1 -0
  106. package/dist/backend/llvm/nullable-fields.test.js +48 -0
  107. package/dist/backend/llvm/nullable-fields.test.js.map +1 -0
  108. package/dist/backend/llvm/serialized-ir-emission.test.d.ts +1 -0
  109. package/dist/backend/llvm/serialized-ir-emission.test.js +52 -0
  110. package/dist/backend/llvm/serialized-ir-emission.test.js.map +1 -0
  111. package/dist/backend/llvm/shapes.d.ts +69 -2
  112. package/dist/backend/llvm/shapes.js +259 -27
  113. package/dist/backend/llvm/shapes.js.map +1 -1
  114. package/dist/backend/llvm/shapes.test.js +114 -5
  115. package/dist/backend/llvm/shapes.test.js.map +1 -1
  116. package/dist/backend/llvm/stack-callbacks.js +2 -3
  117. package/dist/backend/llvm/stack-callbacks.js.map +1 -1
  118. package/dist/backend/llvm/stack-captures.d.ts +3 -1
  119. package/dist/backend/llvm/stack-captures.js +5 -3
  120. package/dist/backend/llvm/stack-captures.js.map +1 -1
  121. package/dist/backend/llvm/stack-unions.test.js +38 -1
  122. package/dist/backend/llvm/stack-unions.test.js.map +1 -1
  123. package/dist/backend/llvm/string-construction.test.js +1 -1
  124. package/dist/backend/llvm/string-key-hash.d.ts +8 -0
  125. package/dist/backend/llvm/string-key-hash.js +59 -0
  126. package/dist/backend/llvm/string-key-hash.js.map +1 -0
  127. package/dist/backend/llvm/string-key-hash.test.d.ts +1 -0
  128. package/dist/backend/llvm/string-key-hash.test.js +34 -0
  129. package/dist/backend/llvm/string-key-hash.test.js.map +1 -0
  130. package/dist/backend/llvm/string-lifetimes.test.js +41 -4
  131. package/dist/backend/llvm/string-lifetimes.test.js.map +1 -1
  132. package/dist/backend/llvm/switch-dispatch.js +1 -1
  133. package/dist/backend/llvm/switch-dispatch.js.map +1 -1
  134. package/dist/backend/llvm/switch-dispatch.test.js +2 -2
  135. package/dist/backend/llvm/switch-dispatch.test.js.map +1 -1
  136. package/dist/backend/may-throw.js +3 -0
  137. package/dist/backend/may-throw.js.map +1 -1
  138. package/dist/backend/may-throw.test.js +1 -1
  139. package/dist/backend/native/cache-warm.d.ts +2 -1
  140. package/dist/backend/native/cache-warm.js.map +1 -1
  141. package/dist/backend/native/contracts.d.ts +3 -2
  142. package/dist/backend/native/contracts.js.map +1 -1
  143. package/dist/backend/native/runtime-inputs.d.ts +1 -1
  144. package/dist/backend/native/runtime-inputs.js +1 -0
  145. package/dist/backend/native/runtime-inputs.js.map +1 -1
  146. package/dist/backend/native-codegen-core.d.ts +2 -1
  147. package/dist/backend/native-codegen-core.js.map +1 -1
  148. package/dist/backend/native-codegen.d.ts +5 -0
  149. package/dist/backend/native-codegen.js +4 -0
  150. package/dist/backend/native-codegen.js.map +1 -1
  151. package/dist/backend/native-codegen.test.js +23 -0
  152. package/dist/backend/native-codegen.test.js.map +1 -1
  153. package/dist/backend/native-link-info-core.d.ts +3 -2
  154. package/dist/backend/native-link-info-core.js.map +1 -1
  155. package/dist/backend/native-link-info.d.ts +2 -1
  156. package/dist/backend/native-link-info.js.map +1 -1
  157. package/dist/backend/native-link-info.test.js +2 -2
  158. package/dist/backend/native-link-info.test.js.map +1 -1
  159. package/dist/backend/native-tools.d.ts +3 -1
  160. package/dist/backend/native-tools.js +0 -1
  161. package/dist/backend/native-tools.js.map +1 -1
  162. package/dist/backend/optimization.d.ts +25 -0
  163. package/dist/backend/optimization.js +21 -0
  164. package/dist/backend/optimization.js.map +1 -0
  165. package/dist/backend/optimization.test.d.ts +1 -0
  166. package/dist/backend/optimization.test.js +24 -0
  167. package/dist/backend/optimization.test.js.map +1 -0
  168. package/dist/backend/runtime-abi.d.ts +2 -2
  169. package/dist/backend/runtime-abi.js +2 -2
  170. package/dist/backend/runtime-pack-core.d.ts +15 -4
  171. package/dist/backend/runtime-pack-core.js +23 -12
  172. package/dist/backend/runtime-pack-core.js.map +1 -1
  173. package/dist/backend/runtime-pack-native.d.ts +7 -3
  174. package/dist/backend/runtime-pack-native.js +0 -3
  175. package/dist/backend/runtime-pack-native.js.map +1 -1
  176. package/dist/backend/runtime-pack-targets.test.js +1 -1
  177. package/dist/backend/runtime-pack.d.ts +20 -2
  178. package/dist/backend/runtime-pack.js +23 -0
  179. package/dist/backend/runtime-pack.js.map +1 -1
  180. package/dist/backend/runtime-pack.test.js +115 -2
  181. package/dist/backend/runtime-pack.test.js.map +1 -1
  182. package/dist/backend/target-diagnostics.test.js +1 -1
  183. package/dist/backend/targets.d.ts +2 -1
  184. package/dist/backend/targets.js +1 -1
  185. package/dist/backend/targets.js.map +1 -1
  186. package/dist/cli/command.js +5 -4
  187. package/dist/cli/command.js.map +1 -1
  188. package/dist/cli/host.d.ts +2 -1
  189. package/dist/cli/usage.d.ts +1 -1
  190. package/dist/cli/usage.js +5 -2
  191. package/dist/cli/usage.js.map +1 -1
  192. package/dist/compile-types.d.ts +5 -2
  193. package/dist/diagnostics/diagnostic.js +10 -8
  194. package/dist/diagnostics/diagnostic.js.map +1 -1
  195. package/dist/executable/executable-cache.d.ts +2 -2
  196. package/dist/executable/executable-cache.js +7 -4
  197. package/dist/executable/executable-cache.js.map +1 -1
  198. package/dist/executable/executable-cache.test.js +20 -0
  199. package/dist/executable/executable-cache.test.js.map +1 -1
  200. package/dist/frontend/lowering/abstract-equality.js +5 -49
  201. package/dist/frontend/lowering/abstract-equality.js.map +1 -1
  202. package/dist/frontend/lowering/array-values.d.ts +23 -0
  203. package/dist/frontend/lowering/array-values.js +129 -0
  204. package/dist/frontend/lowering/array-values.js.map +1 -1
  205. package/dist/frontend/lowering/builtins/errors.js +17 -2
  206. package/dist/frontend/lowering/builtins/errors.js.map +1 -1
  207. package/dist/frontend/lowering/builtins/process.d.ts +6 -17
  208. package/dist/frontend/lowering/builtins/process.js +56 -29
  209. package/dist/frontend/lowering/builtins/process.js.map +1 -1
  210. package/dist/frontend/lowering/caught-value-dispatch.d.ts +11 -0
  211. package/dist/frontend/lowering/caught-value-dispatch.js +87 -0
  212. package/dist/frontend/lowering/caught-value-dispatch.js.map +1 -0
  213. package/dist/frontend/lowering/class-assertions.d.ts +4 -0
  214. package/dist/frontend/lowering/class-assertions.js +12 -4
  215. package/dist/frontend/lowering/class-assertions.js.map +1 -1
  216. package/dist/frontend/lowering/class-callbacks.d.ts +3 -3
  217. package/dist/frontend/lowering/class-callbacks.js +18 -5
  218. package/dist/frontend/lowering/class-callbacks.js.map +1 -1
  219. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +1 -0
  220. package/dist/frontend/lowering/class-dynamic-dispatch.js +4 -1
  221. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  222. package/dist/frontend/lowering/class-method-mutations.d.ts +5 -0
  223. package/dist/frontend/lowering/class-method-mutations.js +472 -0
  224. package/dist/frontend/lowering/class-method-mutations.js.map +1 -0
  225. package/dist/frontend/lowering/class-method-values.js +25 -5
  226. package/dist/frontend/lowering/class-method-values.js.map +1 -1
  227. package/dist/frontend/lowering/class-prototypes.js +8 -2
  228. package/dist/frontend/lowering/class-prototypes.js.map +1 -1
  229. package/dist/frontend/lowering/class-unions.d.ts +16 -0
  230. package/dist/frontend/lowering/class-unions.js +127 -0
  231. package/dist/frontend/lowering/class-unions.js.map +1 -0
  232. package/dist/frontend/lowering/coercions/builders.js +8 -1
  233. package/dist/frontend/lowering/coercions/builders.js.map +1 -1
  234. package/dist/frontend/lowering/coercions/function-adapters.js +2 -0
  235. package/dist/frontend/lowering/coercions/function-adapters.js.map +1 -1
  236. package/dist/frontend/lowering/coercions/identity.d.ts +7 -0
  237. package/dist/frontend/lowering/coercions/identity.js +26 -0
  238. package/dist/frontend/lowering/coercions/identity.js.map +1 -0
  239. package/dist/frontend/lowering/coercions/structural.js +9 -6
  240. package/dist/frontend/lowering/coercions/structural.js.map +1 -1
  241. package/dist/frontend/lowering/collection-narrowing.d.ts +6 -0
  242. package/dist/frontend/lowering/collection-narrowing.js +31 -0
  243. package/dist/frontend/lowering/collection-narrowing.js.map +1 -0
  244. package/dist/frontend/lowering/containers/array-callback-call.d.ts +7 -0
  245. package/dist/frontend/lowering/containers/array-callback-call.js +52 -0
  246. package/dist/frontend/lowering/containers/array-callback-call.js.map +1 -0
  247. package/dist/frontend/lowering/containers/array-callbacks.d.ts +1 -1
  248. package/dist/frontend/lowering/containers/array-callbacks.js +363 -49
  249. package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
  250. package/dist/frontend/lowering/containers/array-concat.d.ts +7 -0
  251. package/dist/frontend/lowering/containers/array-concat.js +130 -0
  252. package/dist/frontend/lowering/containers/array-concat.js.map +1 -0
  253. package/dist/frontend/lowering/containers/array-construction.d.ts +2 -0
  254. package/dist/frontend/lowering/containers/array-construction.js +95 -3
  255. package/dist/frontend/lowering/containers/array-construction.js.map +1 -1
  256. package/dist/frontend/lowering/containers/array-methods.d.ts +1 -11
  257. package/dist/frontend/lowering/containers/array-methods.js +43 -132
  258. package/dist/frontend/lowering/containers/array-methods.js.map +1 -1
  259. package/dist/frontend/lowering/containers/collection-methods.js +10 -1
  260. package/dist/frontend/lowering/containers/collection-methods.js.map +1 -1
  261. package/dist/frontend/lowering/containers/indexed-objects.js +56 -70
  262. package/dist/frontend/lowering/containers/indexed-objects.js.map +1 -1
  263. package/dist/frontend/lowering/cycle-initialization.d.ts +41 -0
  264. package/dist/frontend/lowering/cycle-initialization.js +277 -0
  265. package/dist/frontend/lowering/cycle-initialization.js.map +1 -0
  266. package/dist/frontend/lowering/expressions/evaluation-safety.js +4 -0
  267. package/dist/frontend/lowering/expressions/evaluation-safety.js.map +1 -1
  268. package/dist/frontend/lowering/expressions/object-literals.js +138 -32
  269. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  270. package/dist/frontend/lowering/expressions/union-field-write.d.ts +4 -4
  271. package/dist/frontend/lowering/expressions/union-field-write.js +54 -44
  272. package/dist/frontend/lowering/expressions/union-field-write.js.map +1 -1
  273. package/dist/frontend/lowering/iterator-adapters.d.ts +20 -0
  274. package/dist/frontend/lowering/iterator-adapters.js +605 -0
  275. package/dist/frontend/lowering/iterator-adapters.js.map +1 -0
  276. package/dist/frontend/lowering/lower-array-sort.d.ts +1 -1
  277. package/dist/frontend/lowering/lower-array-sort.js +44 -5
  278. package/dist/frontend/lowering/lower-array-sort.js.map +1 -1
  279. package/dist/frontend/lowering/lower-array-sort.test.d.ts +1 -0
  280. package/dist/frontend/lowering/lower-array-sort.test.js +31 -0
  281. package/dist/frontend/lowering/lower-array-sort.test.js.map +1 -0
  282. package/dist/frontend/lowering/lower-assert.js +7 -0
  283. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  284. package/dist/frontend/lowering/lower-builtin-values.js +1 -0
  285. package/dist/frontend/lowering/lower-builtin-values.js.map +1 -1
  286. package/dist/frontend/lowering/lower-calls.d.ts +3 -3
  287. package/dist/frontend/lowering/lower-calls.js +162 -121
  288. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  289. package/dist/frontend/lowering/lower-classes.d.ts +2 -0
  290. package/dist/frontend/lowering/lower-classes.js +45 -43
  291. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  292. package/dist/frontend/lowering/lower-exprs.d.ts +9 -2
  293. package/dist/frontend/lowering/lower-exprs.js +390 -157
  294. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  295. package/dist/frontend/lowering/lower-functions.js +32 -19
  296. package/dist/frontend/lowering/lower-functions.js.map +1 -1
  297. package/dist/frontend/lowering/lower-inspect.js +26 -2
  298. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  299. package/dist/frontend/lowering/lower-modules.js +10 -2
  300. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  301. package/dist/frontend/lowering/lower-stmts.js +46 -58
  302. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  303. package/dist/frontend/lowering/lowerer.d.ts +37 -0
  304. package/dist/frontend/lowering/lowerer.js +283 -18
  305. package/dist/frontend/lowering/lowerer.js.map +1 -1
  306. package/dist/frontend/lowering/native-ffi.js +3 -1
  307. package/dist/frontend/lowering/native-ffi.js.map +1 -1
  308. package/dist/frontend/lowering/runtime-optional-provenance.d.ts +15 -0
  309. package/dist/frontend/lowering/runtime-optional-provenance.js +40 -0
  310. package/dist/frontend/lowering/runtime-optional-provenance.js.map +1 -0
  311. package/dist/frontend/lowering/sanitize-class-types.test.js +2 -2
  312. package/dist/frontend/lowering/strict-equality.d.ts +9 -0
  313. package/dist/frontend/lowering/strict-equality.js +116 -0
  314. package/dist/frontend/lowering/strict-equality.js.map +1 -0
  315. package/dist/frontend/lowering/surfaces.js +3 -0
  316. package/dist/frontend/lowering/surfaces.js.map +1 -1
  317. package/dist/frontend/lowering/union-comparison.d.ts +5 -0
  318. package/dist/frontend/lowering/union-comparison.js +47 -0
  319. package/dist/frontend/lowering/union-comparison.js.map +1 -0
  320. package/dist/frontend/program.d.ts +38 -2
  321. package/dist/frontend/program.js +440 -59
  322. package/dist/frontend/program.js.map +1 -1
  323. package/dist/frontend/program.test.js +59 -6
  324. package/dist/frontend/program.test.js.map +1 -1
  325. package/dist/frontend/type-mapper.d.ts +1 -1
  326. package/dist/frontend/type-mapper.js +89 -14
  327. package/dist/frontend/type-mapper.js.map +1 -1
  328. package/dist/frontend/type-mapper.test.js +15 -3
  329. package/dist/frontend/type-mapper.test.js.map +1 -1
  330. package/dist/index.js +25 -9
  331. package/dist/index.js.map +1 -1
  332. package/dist/ir/analysis.d.ts +3 -1
  333. package/dist/ir/analysis.js +4 -0
  334. package/dist/ir/analysis.js.map +1 -1
  335. package/dist/ir/builtin-signatures.js +2 -3
  336. package/dist/ir/builtin-signatures.js.map +1 -1
  337. package/dist/ir/constant-tables.test.js +1 -1
  338. package/dist/ir/initializer-bindings.test.js +1 -1
  339. package/dist/ir/ir.d.ts +78 -15
  340. package/dist/ir/ir.js +20 -6
  341. package/dist/ir/ir.js.map +1 -1
  342. package/dist/ir/scalar-records.test.js +1 -1
  343. package/dist/ir/serialize.d.ts +1 -1
  344. package/dist/ir/serialize.js +3 -3
  345. package/dist/ir/serialize.js.map +1 -1
  346. package/dist/ir/traverse.js +8 -0
  347. package/dist/ir/traverse.js.map +1 -1
  348. package/dist/ir/validate.js +118 -20
  349. package/dist/ir/validate.js.map +1 -1
  350. package/dist/ir/validate.test.js +269 -8
  351. package/dist/ir/validate.test.js.map +1 -1
  352. package/dist/library/fence-eval.test.js +1 -1
  353. package/dist/library/int-infer.test.js +4 -4
  354. package/dist/library/library-cache.test.js +5 -5
  355. package/dist/library/library-profile.d.ts +2 -1
  356. package/dist/library/library-profile.js +4 -3
  357. package/dist/library/library-profile.js.map +1 -1
  358. package/dist/native/compiler.js.map +1 -1
  359. package/dist/native/compiler.test.js +2 -2
  360. package/dist/native/library.d.ts +2 -1
  361. package/dist/native/library.js.map +1 -1
  362. package/dist/native/prepare.js +27 -3
  363. package/dist/native/prepare.js.map +1 -1
  364. package/dist/native/sanitizer.d.ts +3 -2
  365. package/dist/native/sanitizer.js +3 -13
  366. package/dist/native/sanitizer.js.map +1 -1
  367. package/package.json +20 -20
  368. package/surface-manifest.json +8 -2
@@ -1,7 +1,10 @@
1
1
  import { boolLit, countedFor, numLit, varRef } from "../../../ir/build.js";
2
+ import { transformStmtList } from "../../../ir/traverse.js";
2
3
  import { InternalCompilerError } from "../../../errors.js";
4
+ import { canAssertClassValue, checkedClassAssertion } from "../class-assertions.js";
3
5
  import * as ts from "../../ts7/adapter.js";
4
- import { BOOL, DYN, F64, STRING, UNDEFINED_T, VOID, arrayOf, funcOf, isUnitType, typeEquals, } from "../../../ir/ir.js";
6
+ import { PoisonError } from "../lowerer.js";
7
+ import { BOOL, DYN, F64, STRING, UNDEFINED_T, VOID, arrayOf, funcOf, isSortValuesElement, isUnitType, typeEquals, } from "../../../ir/ir.js";
5
8
  import { isJsSourceFile, locOf } from "../../program.js";
6
9
  import { buildArraySortFn } from "../lower-array-sort.js";
7
10
  import { arrayIndexPresent, arrayValueRead, arrayValueStore, arrayValueType, currentArrayIndexPresent, } from "../array-values.js";
@@ -70,9 +73,19 @@ export function lowerArrayHofCall(lowerer, call, access, method, elem) {
70
73
  const outElem = method === "filter"
71
74
  ? filterResultElem(lowerer, call, argNode, elem, valueT, booleanFilter)
72
75
  : callbackArrayElement(lowerer, call, fnRet);
73
- const helper = arrayHofHelper(lowerer, method, elem, fnRet, arity, loc, outElem);
76
+ // A filter that re-tags its elements keeps the single union-typed visit.
77
+ const fast = booleanFilter || (method === "filter" && !typeEquals(outElem, elem))
78
+ ? null
79
+ : lowerFastCallback(lowerer, argNode, [valueT], 0, elem, arrayOf(elem), callback);
80
+ const helper = arrayHofHelper(lowerer, method, elem, fnRet, arity, loc, outElem, callbackSite(fast ?? fnArg), fast?.type ?? null);
74
81
  const resultType = method === "map" || method === "filter" ? arrayOf(outElem) : VOID;
75
- return { kind: "call", callee: helper, args: [receiver, fnArg], type: resultType, loc };
82
+ return {
83
+ kind: "call",
84
+ callee: helper,
85
+ args: [receiver, fnArg, ...(fast ? [fast] : [])],
86
+ type: resultType,
87
+ loc,
88
+ };
76
89
  }
77
90
  /** The checker-selected element of a filter result, with the same trust
78
91
  * boundary as the historical narrowing filter: an inferred inline type
@@ -112,13 +125,15 @@ function filterResultElem(lowerer, call, argNode, elem, valueT, booleanFilter) {
112
125
  `unchecked assertion nothing validates at runtime — ${annotateEscape})`);
113
126
  }
114
127
  }
115
- if (valueT.kind !== "union" || lowerer.armTag(valueT.unionId, outElem) < 0) {
128
+ const classRefinement = !booleanFilter && outElem.kind === "object" && canAssertClassValue(lowerer, valueT, outElem);
129
+ if (!classRefinement &&
130
+ (valueT.kind !== "union" || lowerer.armTag(valueT.unionId, outElem) < 0)) {
116
131
  const multiArm = outElem.kind === "union";
117
132
  lowerer.unsupported("SC1090", call, `'.filter' narrowing '${lowerer.fmt(elem)}' elements to ` +
118
133
  `${multiArm ? `the multi-arm '${lowerer.fmt(outElem)}'` : `'${lowerer.fmt(outElem)}'`} ` +
119
134
  `(${multiArm ? "only a SINGLE arm re-tags" : "only a single runtime arm re-tags"} — ${annotateEscape})`);
120
135
  }
121
- if (booleanFilter) {
136
+ if (booleanFilter && valueT.kind === "union") {
122
137
  const arms = lowerer.unions.get(valueT.unionId)?.arms ?? [];
123
138
  if (arms.some((arm) => !typeEquals(arm, outElem) && !isUnitType(arm))) {
124
139
  lowerer.unsupported("SC1090", call, `'.filter(Boolean)' narrowing '${lowerer.fmt(elem)}' to '${lowerer.fmt(outElem)}' ` +
@@ -194,18 +209,193 @@ function filterCond(call, fnRet, loc) {
194
209
  // the runtime's kind-aware ToBoolean.
195
210
  return { kind: "toBool", operand: call, type: BOOL, loc };
196
211
  }
212
+ /** Nested HOFs inside a fast lowering keep their single union visit, so
213
+ * duplication stays linear in nesting depth. */
214
+ let fastLoweringDepth = 0;
215
+ /** Array reads widen elements with undefined so holes and present
216
+ * undefined stay observable, which makes every callback parameter a boxed
217
+ * `T | undefined`. For an inline arrow over a plain element type, lower the
218
+ * callback a second time with the element type itself. The helper then
219
+ * splits each visit on the element state: a present value calls this fast
220
+ * closure with the plain element (no union box, no per-use undefined
221
+ * test), and a hole or present undefined calls the original closure with
222
+ * the undefined arm. Both closures share the same capture boxes and body,
223
+ * so every observable effect is the same; arrows have no own `this`,
224
+ * `arguments` or self binding that could tell the two apart. Any refusal
225
+ * in the second lowering is discarded and keeps the single visit. */
226
+ function lowerFastCallback(lowerer, argNode, lead, elemIndex, elem, arrT, slow, bindUntyped = false, expectedReturn) {
227
+ const valueT = lead[elemIndex];
228
+ if (fastLoweringDepth > 0 ||
229
+ slow.arity <= elemIndex ||
230
+ !ts.isArrowFunction(argNode) ||
231
+ isJsSourceFile(argNode.getSourceFile()) ||
232
+ valueT?.kind !== "union" ||
233
+ typeEquals(valueT, elem) ||
234
+ elem.kind === "union" ||
235
+ elem.kind === "dyn" ||
236
+ elem.kind === "jsval" ||
237
+ isUnitType(elem))
238
+ return null;
239
+ const fastLead = lead.slice();
240
+ fastLead[elemIndex] = elem;
241
+ // The optional-read prepass binds an unannotated element parameter to
242
+ // the array's runtime value type. Rebind it to the plain element for
243
+ // this lowering only.
244
+ const param = argNode.parameters[elemIndex];
245
+ if (!param || param.initializer || param.dotDotDotToken || !ts.isIdentifier(param.name))
246
+ return null;
247
+ const symbol = param.type ? undefined : lowerer.checker.getSymbolAtLocation(param.name);
248
+ const previousBinding = symbol ? lowerer.runtimeOptionalBindingTypes.get(symbol) : undefined;
249
+ if (symbol)
250
+ lowerer.runtimeOptionalBindingTypes.set(symbol, elem);
251
+ const sink = [];
252
+ const previousSink = lowerer.diagSink;
253
+ lowerer.diagSink = sink;
254
+ fastLoweringDepth++;
255
+ let fast;
256
+ try {
257
+ fast = lowerArrayCallback(lowerer, argNode, fastLead, arrT, bindUntyped, expectedReturn);
258
+ }
259
+ catch (e) {
260
+ if (e instanceof PoisonError)
261
+ return null;
262
+ throw e;
263
+ }
264
+ finally {
265
+ fastLoweringDepth--;
266
+ lowerer.diagSink = previousSink;
267
+ if (symbol) {
268
+ if (previousBinding === undefined)
269
+ lowerer.runtimeOptionalBindingTypes.delete(symbol);
270
+ else
271
+ lowerer.runtimeOptionalBindingTypes.set(symbol, previousBinding);
272
+ }
273
+ }
274
+ const fastT = fast.fnArg.type;
275
+ const slowT = slow.fnArg.type;
276
+ if (fast.fnArg.kind !== "closure" ||
277
+ fast.arity !== slow.arity ||
278
+ !typeEquals(fastT.ret, slowT.ret) ||
279
+ !fastT.params.every((param, i) => typeEquals(param, i === elemIndex ? elem : slowT.params[i])))
280
+ return null;
281
+ return fast.fnArg;
282
+ }
283
+ /** `a[i]` holds a value (array state 1): neither a hole nor a present
284
+ * undefined. */
285
+ function presentValue(arr, index, loc) {
286
+ return {
287
+ kind: "bin",
288
+ op: "===",
289
+ left: { kind: "arrayState", arr, index, type: F64, loc },
290
+ right: numLit(1, loc),
291
+ type: BOOL,
292
+ loc,
293
+ };
294
+ }
295
+ /** Route a helper's callback calls through the split visit: every
296
+ * `f(<arrayValueRead a[i]>, ...)` becomes
297
+ * `state(a, i) === 1 ? fast(a[i], ...) : f(undefined, ...)`. The read is
298
+ * the call's only effectful operand (the rest are the loop's index and
299
+ * array locals), so evaluation order is unchanged. The fast closure is an
300
+ * extra trailing parameter. */
301
+ function withFastCallback(fn, fastT, elem) {
302
+ if (!fastT)
303
+ return fn;
304
+ const isValueRead = (e) => e.kind === "ternary" &&
305
+ e.cond.kind === "bin" &&
306
+ e.cond.op === "===" &&
307
+ e.cond.left.kind === "arrayState" &&
308
+ e.cond.right.kind === "numLit" &&
309
+ e.cond.right.value === 1;
310
+ const split = (e) => {
311
+ if (e.kind !== "callValue" || e.callee.kind !== "varRef" || e.callee.localId !== "f.0")
312
+ return null;
313
+ const at = e.args.findIndex(isValueRead);
314
+ if (at < 0)
315
+ return null;
316
+ const read = e.args[at];
317
+ if (read.kind !== "ternary")
318
+ return null;
319
+ const condition = read.cond;
320
+ if (condition.kind !== "bin")
321
+ return null;
322
+ const state = condition.left;
323
+ if (state.kind !== "arrayState")
324
+ return null;
325
+ const fastArgs = e.args.slice();
326
+ fastArgs[at] = {
327
+ kind: "arrayGet",
328
+ arr: state.arr,
329
+ index: state.index,
330
+ type: elem,
331
+ loc: read.loc,
332
+ };
333
+ const slowArgs = e.args.slice();
334
+ slowArgs[at] = read.else_;
335
+ return {
336
+ cond: read.cond,
337
+ fast: { ...e, callee: varRef("fast.0", fastT, e.callee.loc), args: fastArgs },
338
+ slow: { ...e, args: slowArgs },
339
+ };
340
+ };
341
+ const body = transformStmtList(fn.body, {
342
+ stmt: (stmt) => {
343
+ if (stmt.kind !== "exprStmt")
344
+ return stmt;
345
+ const parts = split(stmt.expr);
346
+ if (!parts)
347
+ return stmt;
348
+ return {
349
+ kind: "if",
350
+ cond: parts.cond,
351
+ then: [{ kind: "exprStmt", expr: parts.fast, loc: stmt.loc }],
352
+ else_: [{ kind: "exprStmt", expr: parts.slow, loc: stmt.loc }],
353
+ loc: stmt.loc,
354
+ };
355
+ },
356
+ expr: (expr) => {
357
+ const parts = split(expr);
358
+ if (!parts)
359
+ return expr;
360
+ return {
361
+ kind: "ternary",
362
+ cond: parts.cond,
363
+ then: parts.fast,
364
+ else_: parts.slow,
365
+ type: expr.type,
366
+ loc: expr.loc,
367
+ };
368
+ },
369
+ });
370
+ return {
371
+ ...fn,
372
+ params: [...fn.params, { localId: "fast.0", name: "fast", type: fastT }],
373
+ locals: [...fn.locals, { id: "fast.0", name: "fast", type: fastT, mutable: true }],
374
+ body,
375
+ };
376
+ }
377
+ /** The interning suffix for a callback argument. A literal closure (an
378
+ * inline arrow or function expression) gets a helper of its own, so the
379
+ * helper's only incoming callback is one known function: the backend's
380
+ * constant-callback census then calls it directly and LLVM can inline the
381
+ * callback into the loop (TurboFan's builtin+callback inlining). Callback
382
+ * values keep the shared, type-interned helper. */
383
+ function callbackSite(fnArg) {
384
+ return fnArg.kind === "closure" ? `@${fnArg.fnName}` : "";
385
+ }
197
386
  /** Interned synthetic loop function for one (method, elem, fnRet, arity)
198
387
  * combo. Named `%arr.<method>.<n>` ('%' keeps it out of the user
199
388
  * namespace); rides `liftedFns` into the module like a lifted lambda (it
200
389
  * is a plain function — no captures). */
201
- function arrayHofHelper(lowerer, method, elem, fnRet, arity, loc, outElem = fnRet) {
202
- const key = `${method}:${typeKey(elem)}:${typeKey(fnRet)}:${arity}:${typeKey(outElem)}`;
390
+ function arrayHofHelper(lowerer, method, elem, fnRet, arity, loc, outElem = fnRet, site = "", fastT = null) {
391
+ const key = `${method}:${typeKey(elem)}:${typeKey(fnRet)}:${arity}:${typeKey(outElem)}${site}${fastT ? ":split" : ""}`;
203
392
  const existing = lowerer.arrHofHelpers.get(key);
204
393
  if (existing)
205
394
  return existing;
206
395
  const name = `%arr.${method}.${lowerer.arrHofHelpers.size}`;
207
396
  lowerer.arrHofHelpers.set(key, name);
208
- lowerer.liftedFns.push(buildArrayHofFn(lowerer, name, method, elem, fnRet, arity, loc, outElem));
397
+ const fn = buildArrayHofFn(lowerer, name, method, elem, fnRet, arity, loc, outElem, fastT);
398
+ lowerer.liftedFns.push(fastT ? withFastCallback(fn, fastT, elem) : fn);
209
399
  return name;
210
400
  }
211
401
  /** The TS 5.2+ callable-union array rule: a `T[] | U[]` receiver exposes
@@ -363,7 +553,7 @@ function arrayUnionHofHelper(lowerer, method, receiverT, arrays, callbackT, arit
363
553
  * `arity` is the callback's declared parameter count (1–3): the loop
364
554
  * passes the index and the receiver itself after the element when the
365
555
  * callback names them, exactly the arguments JS supplies. */
366
- function buildArrayHofFn(lowerer, name, method, elem, fnRet, arity, loc, outElem) {
556
+ function buildArrayHofFn(lowerer, name, method, elem, fnRet, arity, loc, outElem, fastT = null) {
367
557
  const arrT = arrayOf(elem);
368
558
  const valueT = arrayValueType(lowerer, elem);
369
559
  const fnT = funcOf([arrayValueType(lowerer, elem), F64, arrT].slice(0, arity), fnRet);
@@ -428,22 +618,111 @@ function buildArrayHofFn(lowerer, name, method, elem, fnRet, arity, loc, outElem
428
618
  { kind: "return", value: varRef("out.0", outT, loc), loc },
429
619
  ];
430
620
  }
621
+ else if (method === "filter" && fastT) {
622
+ // Split visit (outElem === elem): a present value goes to the fast
623
+ // callback as a plain element and is kept as-is; a present undefined
624
+ // goes to the original callback and is kept as undefined.
625
+ const outT = arrayOf(outElem);
626
+ locals.push({ id: "out.0", name: "out", type: outT, mutable: false }, { id: "e.0", name: "e", type: elem, mutable: false });
627
+ returnType = outT;
628
+ const a = varRef("a.0", arrT, loc);
629
+ const i = varRef("i.0", F64, loc);
630
+ const outLength = {
631
+ kind: "arrIntrinsic",
632
+ method: "length",
633
+ receiver: varRef("out.0", outT, loc),
634
+ args: [],
635
+ type: F64,
636
+ loc,
637
+ };
638
+ const missing = getElem.else_;
639
+ const callFast = (arg) => ({
640
+ kind: "callValue",
641
+ callee: varRef("fast.0", fastT, loc),
642
+ args: [arg, i, a].slice(0, arity),
643
+ type: fnRet,
644
+ loc,
645
+ });
646
+ body = [
647
+ {
648
+ kind: "varDecl",
649
+ localId: "out.0",
650
+ init: { kind: "arrayLit", elems: [], type: outT, loc },
651
+ loc,
652
+ },
653
+ readLen,
654
+ forLoop([
655
+ {
656
+ kind: "if",
657
+ cond: hasElem,
658
+ then: [
659
+ {
660
+ kind: "if",
661
+ cond: presentValue(a, i, loc),
662
+ then: [
663
+ {
664
+ kind: "varDecl",
665
+ localId: "e.0",
666
+ init: { kind: "arrayGet", arr: a, index: i, type: elem, loc },
667
+ loc,
668
+ },
669
+ {
670
+ kind: "if",
671
+ cond: filterCond(callFast(varRef("e.0", elem, loc)), fnRet, loc),
672
+ then: [
673
+ arrayValueStore(lowerer, varRef("out.0", outT, loc), outLength, varRef("e.0", elem, loc), outElem, loc),
674
+ ],
675
+ else_: null,
676
+ loc,
677
+ },
678
+ ],
679
+ else_: [
680
+ {
681
+ kind: "if",
682
+ cond: filterCond(callF(missing), fnRet, loc),
683
+ then: [
684
+ {
685
+ kind: "arraySetUndefined",
686
+ arr: varRef("out.0", outT, loc),
687
+ index: outLength,
688
+ loc,
689
+ },
690
+ ],
691
+ else_: null,
692
+ loc,
693
+ },
694
+ ],
695
+ loc,
696
+ },
697
+ ],
698
+ else_: null,
699
+ loc,
700
+ },
701
+ ]),
702
+ { kind: "return", value: varRef("out.0", outT, loc), loc },
703
+ ];
704
+ }
431
705
  else if (method === "filter") {
432
706
  const outT = arrayOf(outElem);
433
707
  locals.push({ id: "out.0", name: "out", type: outT, mutable: false }, { id: "v.0", name: "v", type: valueT, mutable: false });
434
708
  returnType = outT;
709
+ const classView = !typeEquals(outElem, elem) && outElem.kind === "object"
710
+ ? checkedClassAssertion(lowerer, varRef("v.0", valueT, loc), outElem, loc)
711
+ : null;
435
712
  const retained = typeEquals(outElem, elem)
436
713
  ? varRef("v.0", valueT, loc)
437
- : valueT.kind === "union"
438
- ? {
439
- kind: "unionNarrow",
440
- unionId: valueT.unionId,
441
- tag: lowerer.armTag(valueT.unionId, outElem),
442
- value: varRef("v.0", valueT, loc),
443
- type: outElem,
444
- loc,
445
- }
446
- : varRef("v.0", valueT, loc);
714
+ : classView !== null
715
+ ? classView
716
+ : valueT.kind === "union"
717
+ ? {
718
+ kind: "unionNarrow",
719
+ unionId: valueT.unionId,
720
+ tag: lowerer.armTag(valueT.unionId, outElem),
721
+ value: varRef("v.0", valueT, loc),
722
+ type: outElem,
723
+ loc,
724
+ }
725
+ : varRef("v.0", valueT, loc);
447
726
  body = [
448
727
  {
449
728
  kind: "varDecl",
@@ -539,13 +818,15 @@ export function lowerArrayFindLikeCall(lowerer, call, access, method, elem, bind
539
818
  method === "every" ||
540
819
  method === "findIndex" ||
541
820
  method === "findLastIndex") {
821
+ const fast = lowerFastCallback(lowerer, argNode, [arrayValueType(lowerer, elem)], 0, elem, arrT, { fnArg, arity }, bindUntyped);
822
+ const fastT = fast?.type ?? null;
542
823
  const helper = method === "findIndex" || method === "findLastIndex"
543
- ? findIndexHelper(lowerer, elem, fnRet, arity, last, loc)
544
- : someEveryHelper(lowerer, method, elem, fnRet, arity, loc);
824
+ ? findIndexHelper(lowerer, elem, fnRet, arity, last, loc, callbackSite(fast ?? fnArg), fastT)
825
+ : someEveryHelper(lowerer, method, elem, fnRet, arity, loc, callbackSite(fast ?? fnArg), fastT);
545
826
  return {
546
827
  kind: "call",
547
828
  callee: helper,
548
- args: [receiver, fnArg],
829
+ args: [receiver, fnArg, ...(fast ? [fast] : [])],
549
830
  type: method === "findIndex" || method === "findLastIndex" ? F64 : BOOL,
550
831
  loc,
551
832
  };
@@ -581,10 +862,12 @@ export function lowerArrayFindLikeCall(lowerer, call, access, method, elem, bind
581
862
  lowerer.unsupported("SC1090", call, `'.${method}' result narrowing without a predicate over its element`);
582
863
  }
583
864
  retag = lowerer.narrowedRetagHelper(call, valueT.unionId, resultT.unionId, loc);
584
- if (retag === null)
865
+ const present = lowerer.stripUndefinedArm(resultT);
866
+ if (retag === null &&
867
+ !(present.kind === "object" && canAssertClassValue(lowerer, valueT, present)))
585
868
  lowerer.unsupported("SC1090", call, `'.${method}' narrowing to an incompatible result layout`);
586
869
  }
587
- const helper = findHelper(lowerer, elem, resultT, undefTag, fnRet, arity, last, loc, retag);
870
+ const helper = findHelper(lowerer, elem, resultT, undefTag, fnRet, arity, last, loc, retag, callbackSite(fnArg));
588
871
  return { kind: "call", callee: helper, args: [receiver, fnArg], type: resultT, loc };
589
872
  }
590
873
  /** ToBoolean of a predicate result inside a synthesized HOF helper — the
@@ -603,9 +886,9 @@ function predicateToBoolean(e) {
603
886
  * for (i = 0; i < n; i++) { v = a[i]; if (f(v)) return <v as result arm>; }
604
887
  * return <undefined arm>;
605
888
  */
606
- function findHelper(lowerer, elem, resultT, undefTag, fnRet, arity, last, loc, retag) {
889
+ function findHelper(lowerer, elem, resultT, undefTag, fnRet, arity, last, loc, retag, site = "") {
607
890
  const method = last ? "findLast" : "find";
608
- const key = `${method}:${typeKey(elem)}:${typeKey(resultT)}:${typeKey(fnRet)}:${arity}`;
891
+ const key = `${method}:${typeKey(elem)}:${typeKey(resultT)}:${typeKey(fnRet)}:${arity}${site}`;
609
892
  const existing = lowerer.arrHofHelpers.get(key);
610
893
  if (existing)
611
894
  return existing;
@@ -615,8 +898,14 @@ function findHelper(lowerer, elem, resultT, undefTag, fnRet, arity, last, loc, r
615
898
  const fnT = funcOf([arrayValueType(lowerer, elem), F64, arrT].slice(0, arity), fnRet);
616
899
  const valueT = arrayValueType(lowerer, elem);
617
900
  const v = varRef("v.0", valueT, loc);
901
+ const present = lowerer.stripUndefinedArm(resultT);
902
+ // A successful inferred class predicate may select a descendant of a
903
+ // stored base arm. Keep the value read before the callback mutated the array.
904
+ const classView = retag === null && !lowerer.coercibleValue(valueT, resultT) && present.kind === "object"
905
+ ? checkedClassAssertion(lowerer, v, present, loc)
906
+ : null;
618
907
  const found = retag === null
619
- ? lowerer.coerceToExpected(v, resultT)
908
+ ? lowerer.coerceToExpected(classView ?? v, resultT)
620
909
  : { kind: "call", callee: retag, args: [v], type: resultT, loc };
621
910
  const miss = {
622
911
  kind: "unionWrap",
@@ -668,9 +957,9 @@ function findHelper(lowerer, elem, resultT, undefTag, fnRet, arity, last, loc, r
668
957
  *
669
958
  * n = a.length; for (...) if (f(a[i], i, a)) return i; return -1;
670
959
  */
671
- function findIndexHelper(lowerer, elem, fnRet, arity, last, loc) {
960
+ function findIndexHelper(lowerer, elem, fnRet, arity, last, loc, site = "", fastT = null) {
672
961
  const method = last ? "findLastIndex" : "findIndex";
673
- const key = `${method}:${typeKey(elem)}:${typeKey(fnRet)}:${arity}`;
962
+ const key = `${method}:${typeKey(elem)}:${typeKey(fnRet)}:${arity}${site}${fastT ? ":split" : ""}`;
674
963
  const existing = lowerer.arrHofHelpers.get(key);
675
964
  if (existing)
676
965
  return existing;
@@ -695,14 +984,14 @@ function findIndexHelper(lowerer, elem, fnRet, arity, last, loc) {
695
984
  loop,
696
985
  { kind: "return", value: { kind: "numLit", value: -1, type: F64, loc }, loc },
697
986
  ];
698
- lowerer.liftedFns.push({
987
+ lowerer.liftedFns.push(withFastCallback({
699
988
  name,
700
989
  params: arrayCallbackParams(arrT, fnT),
701
990
  returnType: F64,
702
991
  locals: [...arrayCallbackLocals(arrT, fnT)],
703
992
  body,
704
993
  loc,
705
- });
994
+ }, fastT, elem));
706
995
  return name;
707
996
  }
708
997
  /** The some/every loops — short-circuit early returns, JS-exact:
@@ -710,8 +999,8 @@ function findIndexHelper(lowerer, elem, fnRet, arity, last, loc) {
710
999
  * some: n = a.length; for (...) if (f(a[i])) return true; return false;
711
1000
  * every: n = a.length; for (...) if (!f(a[i])) return false; return true;
712
1001
  */
713
- function someEveryHelper(lowerer, method, elem, fnRet, arity, loc) {
714
- const key = `${method}:${typeKey(elem)}:${typeKey(fnRet)}:${arity}`;
1002
+ function someEveryHelper(lowerer, method, elem, fnRet, arity, loc, site = "", fastT = null) {
1003
+ const key = `${method}:${typeKey(elem)}:${typeKey(fnRet)}:${arity}${site}${fastT ? ":split" : ""}`;
715
1004
  const existing = lowerer.arrHofHelpers.get(key);
716
1005
  if (existing)
717
1006
  return existing;
@@ -743,14 +1032,14 @@ function someEveryHelper(lowerer, method, elem, fnRet, arity, loc) {
743
1032
  ]),
744
1033
  { kind: "return", value: boolLit(method !== "some", loc), loc },
745
1034
  ];
746
- lowerer.liftedFns.push({
1035
+ lowerer.liftedFns.push(withFastCallback({
747
1036
  name,
748
1037
  params: arrayCallbackParams(arrT, fnT),
749
1038
  returnType: BOOL,
750
1039
  locals: [...arrayCallbackLocals(arrT, fnT)],
751
1040
  body,
752
1041
  loc,
753
- });
1042
+ }, fastT, elem));
754
1043
  return name;
755
1044
  }
756
1045
  /** `a.flatMap(f)` — map plus a one-level flatten. A callback returning
@@ -794,11 +1083,28 @@ export function lowerArrayFlatMapCall(lowerer, call, access, elem) {
794
1083
  lowerer.badType(call, lowerer.typeOf(call));
795
1084
  requireProducedArrayElement(lowerer, call, "'.flatMap()'", fnRet);
796
1085
  const outElem = callbackArrayElement(lowerer, call, fnRet);
797
- const helper = arrayHofHelper(lowerer, "flatMap", elem, fnRet, arity, loc, outElem);
798
- return { kind: "call", callee: helper, args: [receiver, fnArg], type: arrayOf(outElem), loc };
1086
+ const fast = lowerFastCallback(lowerer, argNode, [arrayValueType(lowerer, elem)], 0, elem, arrT, { fnArg, arity });
1087
+ const helper = arrayHofHelper(lowerer, "flatMap", elem, fnRet, arity, loc, outElem, callbackSite(fast ?? fnArg), fast?.type ?? null);
1088
+ return {
1089
+ kind: "call",
1090
+ callee: helper,
1091
+ args: [receiver, fnArg, ...(fast ? [fast] : [])],
1092
+ type: arrayOf(outElem),
1093
+ loc,
1094
+ };
799
1095
  }
800
- const helper = flatMapHelper(lowerer, elem, fnRet, arity, loc);
801
- return { kind: "call", callee: helper, args: [receiver, fnArg], type: fnRet, loc };
1096
+ const fast = lowerFastCallback(lowerer, argNode, [arrayValueType(lowerer, elem)], 0, elem, arrT, {
1097
+ fnArg,
1098
+ arity,
1099
+ });
1100
+ const helper = flatMapHelper(lowerer, elem, fnRet, arity, loc, callbackSite(fast ?? fnArg), fast?.type ?? null);
1101
+ return {
1102
+ kind: "call",
1103
+ callee: helper,
1104
+ args: [receiver, fnArg, ...(fast ? [fast] : [])],
1105
+ type: fnRet,
1106
+ loc,
1107
+ };
802
1108
  }
803
1109
  /** The flatMap loop (array-returning callback), from existing IR nodes:
804
1110
  *
@@ -809,8 +1115,8 @@ export function lowerArrayFlatMapCall(lowerer, call, access, elem) {
809
1115
  * }
810
1116
  * return out;
811
1117
  */
812
- function flatMapHelper(lowerer, elem, fnRet, arity, loc) {
813
- const key = `flatMap:${typeKey(elem)}:${typeKey(fnRet)}:${arity}`;
1118
+ function flatMapHelper(lowerer, elem, fnRet, arity, loc, site = "", fastT = null) {
1119
+ const key = `flatMap:${typeKey(elem)}:${typeKey(fnRet)}:${arity}${site}${fastT ? ":split" : ""}`;
814
1120
  const existing = lowerer.arrHofHelpers.get(key);
815
1121
  if (existing)
816
1122
  return existing;
@@ -909,7 +1215,7 @@ function flatMapHelper(lowerer, elem, fnRet, arity, loc) {
909
1215
  ]),
910
1216
  { kind: "return", value: varRef("out.0", fnRet, loc), loc },
911
1217
  ];
912
- lowerer.liftedFns.push({
1218
+ lowerer.liftedFns.push(withFastCallback({
913
1219
  name,
914
1220
  params: arrayCallbackParams(arrT, fnT),
915
1221
  returnType: fnRet,
@@ -923,7 +1229,7 @@ function flatMapHelper(lowerer, elem, fnRet, arity, loc) {
923
1229
  ],
924
1230
  body,
925
1231
  loc,
926
- });
1232
+ }, fastT, elem));
927
1233
  return name;
928
1234
  }
929
1235
  /** `a.reduce(f)` / `a.reduce(f, init)` and reduceRight — both declared
@@ -944,10 +1250,15 @@ export function lowerArrayReduceCall(lowerer, call, access, method, elem) {
944
1250
  if (accT.kind === "void" || accT.kind === "func")
945
1251
  lowerer.badType(call, lowerer.typeOf(call));
946
1252
  const { fnArg, arity } = lowerArrayCallback(lowerer, argNode, [accT, arrayValueType(lowerer, elem)], arrT, false, accT);
947
- const helper = reduceHelper(lowerer, method, elem, accT, fnArg.type.ret, arity, hasInit, loc);
1253
+ const fast = lowerFastCallback(lowerer, argNode, [accT, arrayValueType(lowerer, elem)], 1, elem, arrT, { fnArg, arity }, false, accT);
1254
+ const helper = reduceHelper(lowerer, method, elem, accT, fnArg.type.ret, arity, hasInit, loc, callbackSite(fast ?? fnArg), fast?.type ?? null);
948
1255
  const args = [receiver, fnArg];
949
1256
  if (hasInit)
950
1257
  args.push(lowerer.lowerExprExpecting(call.arguments[1], accT));
1258
+ // The fast closure is created last; making a closure has no observable
1259
+ // effect, so the initial value still evaluates right after the callback.
1260
+ if (fast)
1261
+ args.push(fast);
951
1262
  return { kind: "call", callee: helper, args, type: accT, loc };
952
1263
  }
953
1264
  /** The reduce/reduceRight loops, from existing IR nodes:
@@ -960,8 +1271,8 @@ export function lowerArrayReduceCall(lowerer, call, access, method, elem) {
960
1271
  * reduce walks 0→n-1, reduceRight n-1→0; the seed without an initial
961
1272
  * value is a[0] / a[n-1] and the loop starts one past it. The empty-array
962
1273
  * TypeError message is Node's, byte for byte. */
963
- function reduceHelper(lowerer, method, elem, accT, fnRet, arity, hasInit, loc) {
964
- const key = `${method}:${typeKey(elem)}:${typeKey(accT)}:${typeKey(fnRet)}:${arity}:${hasInit ? "init" : "seed"}`;
1274
+ function reduceHelper(lowerer, method, elem, accT, fnRet, arity, hasInit, loc, site = "", fastT = null) {
1275
+ const key = `${method}:${typeKey(elem)}:${typeKey(accT)}:${typeKey(fnRet)}:${arity}:${hasInit ? "init" : "seed"}${site}${fastT ? ":split" : ""}`;
965
1276
  const existing = lowerer.arrHofHelpers.get(key);
966
1277
  if (existing)
967
1278
  return existing;
@@ -1101,7 +1412,7 @@ function reduceHelper(lowerer, method, elem, accT, fnRet, arity, hasInit, loc) {
1101
1412
  loop,
1102
1413
  { kind: "return", value: varRef("acc.0", accT, loc), loc },
1103
1414
  ];
1104
- lowerer.liftedFns.push({ name, params, returnType: accT, locals, body, loc });
1415
+ lowerer.liftedFns.push(withFastCallback({ name, params, returnType: accT, locals, body, loc }, fastT, elem));
1105
1416
  return name;
1106
1417
  }
1107
1418
  /** `a.sort(cmp)` / `a.toSorted(cmp)`, desugared to an interned synthetic
@@ -1196,13 +1507,16 @@ export function lowerArraySortCall(lowerer, call, access, elem, arrT) {
1196
1507
  lowerer.badType(argNode, lowerer.typeOf(argNode));
1197
1508
  }
1198
1509
  const arity = fnArg.type.params.length;
1199
- const key = `${method}:${typeKey(elem)}:${arity}`;
1510
+ // The runtime sorts raw slots without per-move reference counting; this
1511
+ // beats the IR merge sort even when its comparator call becomes direct.
1512
+ const native = isSortValuesElement(elem, elem.kind === "union" ? lowerer.unions.get(elem.unionId)?.arms : undefined);
1513
+ const key = `${method}:${typeKey(elem)}:${arity}${native ? ":native" : ""}`;
1200
1514
  let helper = lowerer.arrHofHelpers.get(key);
1201
1515
  if (!helper) {
1202
1516
  helper = `%arr.${method}.${lowerer.arrHofHelpers.size}`;
1203
1517
  lowerer.arrHofHelpers.set(key, helper);
1204
1518
  const undefinedTag = elem.kind === "union" ? lowerer.armTag(elem.unionId, UNDEFINED_T) : -1;
1205
- lowerer.liftedFns.push(buildArraySortFn(helper, elem, arity, copyFirst, undefinedTag >= 0 ? undefinedTag : null, loc));
1519
+ lowerer.liftedFns.push(buildArraySortFn(helper, elem, arity, copyFirst, undefinedTag >= 0 ? undefinedTag : null, loc, native));
1206
1520
  }
1207
1521
  return { kind: "call", callee: helper, args: [receiver, fnArg], type: arrT, loc };
1208
1522
  }