@scriptc/compiler 0.2.5 → 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 (520) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +62 -48
  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/executable-features.js +1 -0
  11. package/dist/backend/executable-features.js.map +1 -1
  12. package/dist/backend/link-plan-core.d.ts +4 -1
  13. package/dist/backend/link-plan-core.js +16 -3
  14. package/dist/backend/link-plan-core.js.map +1 -1
  15. package/dist/backend/link-plan.d.ts +3 -1
  16. package/dist/backend/link-plan.js +3 -0
  17. package/dist/backend/link-plan.js.map +1 -1
  18. package/dist/backend/llvm/alloc.d.ts +40 -0
  19. package/dist/backend/llvm/alloc.js +205 -0
  20. package/dist/backend/llvm/alloc.js.map +1 -0
  21. package/dist/backend/llvm/alloc.test.d.ts +1 -0
  22. package/dist/backend/llvm/alloc.test.js +102 -0
  23. package/dist/backend/llvm/alloc.test.js.map +1 -0
  24. package/dist/backend/llvm/byte-numbers.js +32 -4
  25. package/dist/backend/llvm/byte-numbers.js.map +1 -1
  26. package/dist/backend/llvm/byte-windows.d.ts +31 -0
  27. package/dist/backend/llvm/byte-windows.js +334 -0
  28. package/dist/backend/llvm/byte-windows.js.map +1 -0
  29. package/dist/backend/llvm/byte-windows.test.d.ts +1 -0
  30. package/dist/backend/llvm/byte-windows.test.js +244 -0
  31. package/dist/backend/llvm/byte-windows.test.js.map +1 -0
  32. package/dist/backend/llvm/call-lifetimes.d.ts +17 -5
  33. package/dist/backend/llvm/call-lifetimes.js +58 -24
  34. package/dist/backend/llvm/call-lifetimes.js.map +1 -1
  35. package/dist/backend/llvm/call-lifetimes.test.js +170 -0
  36. package/dist/backend/llvm/call-lifetimes.test.js.map +1 -1
  37. package/dist/backend/llvm/classes.d.ts +18 -2
  38. package/dist/backend/llvm/classes.js +115 -41
  39. package/dist/backend/llvm/classes.js.map +1 -1
  40. package/dist/backend/llvm/classes.test.d.ts +1 -0
  41. package/dist/backend/llvm/classes.test.js +132 -0
  42. package/dist/backend/llvm/classes.test.js.map +1 -0
  43. package/dist/backend/llvm/common.d.ts +13 -0
  44. package/dist/backend/llvm/common.js +30 -0
  45. package/dist/backend/llvm/common.js.map +1 -1
  46. package/dist/backend/llvm/constant-callbacks.d.ts +27 -0
  47. package/dist/backend/llvm/constant-callbacks.js +450 -0
  48. package/dist/backend/llvm/constant-callbacks.js.map +1 -0
  49. package/dist/backend/llvm/constant-callbacks.test.d.ts +1 -0
  50. package/dist/backend/llvm/constant-callbacks.test.js +261 -0
  51. package/dist/backend/llvm/constant-callbacks.test.js.map +1 -0
  52. package/dist/backend/llvm/dense-array-access.d.ts +29 -0
  53. package/dist/backend/llvm/dense-array-access.js +335 -0
  54. package/dist/backend/llvm/dense-array-access.js.map +1 -0
  55. package/dist/backend/llvm/dense-array-access.test.d.ts +1 -0
  56. package/dist/backend/llvm/dense-array-access.test.js +149 -0
  57. package/dist/backend/llvm/dense-array-access.test.js.map +1 -0
  58. package/dist/backend/llvm/dyn.d.ts +35 -1
  59. package/dist/backend/llvm/dyn.js +196 -35
  60. package/dist/backend/llvm/dyn.js.map +1 -1
  61. package/dist/backend/llvm/emitter.d.ts +143 -4
  62. package/dist/backend/llvm/emitter.js +882 -136
  63. package/dist/backend/llvm/emitter.js.map +1 -1
  64. package/dist/backend/llvm/emitter.test.js +82 -14
  65. package/dist/backend/llvm/emitter.test.js.map +1 -1
  66. package/dist/backend/llvm/expr-async.js +58 -4
  67. package/dist/backend/llvm/expr-async.js.map +1 -1
  68. package/dist/backend/llvm/expr-async.test.d.ts +1 -0
  69. package/dist/backend/llvm/expr-async.test.js +62 -0
  70. package/dist/backend/llvm/expr-async.test.js.map +1 -0
  71. package/dist/backend/llvm/expr-bytes.js +11 -0
  72. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  73. package/dist/backend/llvm/expr-calls.js +151 -25
  74. package/dist/backend/llvm/expr-calls.js.map +1 -1
  75. package/dist/backend/llvm/expr-containers.js +37 -14
  76. package/dist/backend/llvm/expr-containers.js.map +1 -1
  77. package/dist/backend/llvm/expr-control.js +92 -2
  78. package/dist/backend/llvm/expr-control.js.map +1 -1
  79. package/dist/backend/llvm/expr-dispatch.js +2 -0
  80. package/dist/backend/llvm/expr-dispatch.js.map +1 -1
  81. package/dist/backend/llvm/expr-dynamic.js +210 -28
  82. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  83. package/dist/backend/llvm/expr-primitives.d.ts +1 -1
  84. package/dist/backend/llvm/expr-primitives.js +58 -23
  85. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  86. package/dist/backend/llvm/expr-primitives.test.js +1 -1
  87. package/dist/backend/llvm/expr-records.js +3 -3
  88. package/dist/backend/llvm/expr-records.js.map +1 -1
  89. package/dist/backend/llvm/expr-stream-bridges.js +59 -2
  90. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  91. package/dist/backend/llvm/expr-stream-bridges.test.js +1 -1
  92. package/dist/backend/llvm/integer-remainder.d.ts +18 -0
  93. package/dist/backend/llvm/integer-remainder.js +117 -0
  94. package/dist/backend/llvm/integer-remainder.js.map +1 -0
  95. package/dist/backend/llvm/layouts.d.ts +2 -1
  96. package/dist/backend/llvm/layouts.js +4 -3
  97. package/dist/backend/llvm/layouts.js.map +1 -1
  98. package/dist/backend/llvm/lazy-captures.d.ts +16 -0
  99. package/dist/backend/llvm/lazy-captures.js +96 -0
  100. package/dist/backend/llvm/lazy-captures.js.map +1 -0
  101. package/dist/backend/llvm/lazy-captures.test.d.ts +1 -0
  102. package/dist/backend/llvm/lazy-captures.test.js +78 -0
  103. package/dist/backend/llvm/lazy-captures.test.js.map +1 -0
  104. package/dist/backend/llvm/lib-abi.js +7 -0
  105. package/dist/backend/llvm/lib-abi.js.map +1 -1
  106. package/dist/backend/llvm/lib-dispatch.js +7 -22
  107. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  108. package/dist/backend/llvm/lib-filesystem.js +3 -4
  109. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  110. package/dist/backend/llvm/lib-shared.js +15 -0
  111. package/dist/backend/llvm/lib-shared.js.map +1 -1
  112. package/dist/backend/llvm/local-array-reads.d.ts +13 -3
  113. package/dist/backend/llvm/local-array-reads.js +159 -77
  114. package/dist/backend/llvm/local-array-reads.js.map +1 -1
  115. package/dist/backend/llvm/local-array-reads.test.js +105 -4
  116. package/dist/backend/llvm/local-array-reads.test.js.map +1 -1
  117. package/dist/backend/llvm/local-union-storage.d.ts +5 -1
  118. package/dist/backend/llvm/local-union-storage.js +48 -6
  119. package/dist/backend/llvm/local-union-storage.js.map +1 -1
  120. package/dist/backend/llvm/local-union-storage.test.js +91 -4
  121. package/dist/backend/llvm/local-union-storage.test.js.map +1 -1
  122. package/dist/backend/llvm/loop-array-borrows.d.ts +11 -0
  123. package/dist/backend/llvm/loop-array-borrows.js +70 -0
  124. package/dist/backend/llvm/loop-array-borrows.js.map +1 -0
  125. package/dist/backend/llvm/loop-array-borrows.test.d.ts +1 -0
  126. package/dist/backend/llvm/loop-array-borrows.test.js +145 -0
  127. package/dist/backend/llvm/loop-array-borrows.test.js.map +1 -0
  128. package/dist/backend/llvm/map-read-lifetimes.d.ts +5 -0
  129. package/dist/backend/llvm/map-read-lifetimes.js +20 -5
  130. package/dist/backend/llvm/map-read-lifetimes.js.map +1 -1
  131. package/dist/backend/llvm/map-read-lifetimes.test.js +1 -1
  132. package/dist/backend/llvm/nullable-fields.d.ts +28 -0
  133. package/dist/backend/llvm/nullable-fields.js +45 -0
  134. package/dist/backend/llvm/nullable-fields.js.map +1 -0
  135. package/dist/backend/llvm/nullable-fields.test.d.ts +1 -0
  136. package/dist/backend/llvm/nullable-fields.test.js +48 -0
  137. package/dist/backend/llvm/nullable-fields.test.js.map +1 -0
  138. package/dist/backend/llvm/reference-effects.d.ts +2 -1
  139. package/dist/backend/llvm/reference-effects.js +7 -0
  140. package/dist/backend/llvm/reference-effects.js.map +1 -1
  141. package/dist/backend/llvm/serialized-ir-emission.test.d.ts +1 -0
  142. package/dist/backend/llvm/serialized-ir-emission.test.js +52 -0
  143. package/dist/backend/llvm/serialized-ir-emission.test.js.map +1 -0
  144. package/dist/backend/llvm/shapes.d.ts +73 -3
  145. package/dist/backend/llvm/shapes.js +281 -34
  146. package/dist/backend/llvm/shapes.js.map +1 -1
  147. package/dist/backend/llvm/shapes.test.js +114 -5
  148. package/dist/backend/llvm/shapes.test.js.map +1 -1
  149. package/dist/backend/llvm/split-loops.d.ts +48 -0
  150. package/dist/backend/llvm/split-loops.js +183 -0
  151. package/dist/backend/llvm/split-loops.js.map +1 -0
  152. package/dist/backend/llvm/split.js +0 -7
  153. package/dist/backend/llvm/split.js.map +1 -1
  154. package/dist/backend/llvm/split.test.js +66 -2
  155. package/dist/backend/llvm/split.test.js.map +1 -1
  156. package/dist/backend/llvm/stack-callbacks.d.ts +14 -0
  157. package/dist/backend/llvm/stack-callbacks.js +72 -0
  158. package/dist/backend/llvm/stack-callbacks.js.map +1 -0
  159. package/dist/backend/llvm/stack-captures.d.ts +27 -0
  160. package/dist/backend/llvm/stack-captures.js +152 -0
  161. package/dist/backend/llvm/stack-captures.js.map +1 -0
  162. package/dist/backend/llvm/stack-unions.test.js +38 -1
  163. package/dist/backend/llvm/stack-unions.test.js.map +1 -1
  164. package/dist/backend/llvm/string-construction.test.js +1 -1
  165. package/dist/backend/llvm/string-key-hash.d.ts +8 -0
  166. package/dist/backend/llvm/string-key-hash.js +59 -0
  167. package/dist/backend/llvm/string-key-hash.js.map +1 -0
  168. package/dist/backend/llvm/string-key-hash.test.d.ts +1 -0
  169. package/dist/backend/llvm/string-key-hash.test.js +34 -0
  170. package/dist/backend/llvm/string-key-hash.test.js.map +1 -0
  171. package/dist/backend/llvm/string-lifetimes.test.js +48 -7
  172. package/dist/backend/llvm/string-lifetimes.test.js.map +1 -1
  173. package/dist/backend/llvm/string-slices.d.ts +20 -0
  174. package/dist/backend/llvm/string-slices.js +87 -0
  175. package/dist/backend/llvm/string-slices.js.map +1 -0
  176. package/dist/backend/llvm/string-slices.test.d.ts +1 -0
  177. package/dist/backend/llvm/string-slices.test.js +98 -0
  178. package/dist/backend/llvm/string-slices.test.js.map +1 -0
  179. package/dist/backend/llvm/switch-dispatch.js +1 -1
  180. package/dist/backend/llvm/switch-dispatch.js.map +1 -1
  181. package/dist/backend/llvm/switch-dispatch.test.js +2 -2
  182. package/dist/backend/llvm/switch-dispatch.test.js.map +1 -1
  183. package/dist/backend/llvm/walkers.d.ts +4 -14
  184. package/dist/backend/llvm/walkers.js +53 -311
  185. package/dist/backend/llvm/walkers.js.map +1 -1
  186. package/dist/backend/may-throw.js +4 -1
  187. package/dist/backend/may-throw.js.map +1 -1
  188. package/dist/backend/may-throw.test.js +1 -1
  189. package/dist/backend/native/cache-warm.d.ts +2 -1
  190. package/dist/backend/native/cache-warm.js.map +1 -1
  191. package/dist/backend/native/contracts.d.ts +5 -2
  192. package/dist/backend/native/contracts.js.map +1 -1
  193. package/dist/backend/native/executable.js +12 -4
  194. package/dist/backend/native/executable.js.map +1 -1
  195. package/dist/backend/native/runtime-inputs.d.ts +1 -1
  196. package/dist/backend/native/runtime-inputs.js +3 -0
  197. package/dist/backend/native/runtime-inputs.js.map +1 -1
  198. package/dist/backend/native-codegen-core.d.ts +7 -0
  199. package/dist/backend/native-codegen-core.js +21 -0
  200. package/dist/backend/native-codegen-core.js.map +1 -1
  201. package/dist/backend/native-codegen.d.ts +9 -0
  202. package/dist/backend/native-codegen.js +38 -18
  203. package/dist/backend/native-codegen.js.map +1 -1
  204. package/dist/backend/native-codegen.test.js +70 -2
  205. package/dist/backend/native-codegen.test.js.map +1 -1
  206. package/dist/backend/native-link-info-core.d.ts +4 -2
  207. package/dist/backend/native-link-info-core.js.map +1 -1
  208. package/dist/backend/native-link-info.d.ts +2 -1
  209. package/dist/backend/native-link-info.js.map +1 -1
  210. package/dist/backend/native-link-info.test.js +2 -2
  211. package/dist/backend/native-link-info.test.js.map +1 -1
  212. package/dist/backend/native-tools.d.ts +6 -2
  213. package/dist/backend/native-tools.js +6 -5
  214. package/dist/backend/native-tools.js.map +1 -1
  215. package/dist/backend/optimization.d.ts +25 -0
  216. package/dist/backend/optimization.js +21 -0
  217. package/dist/backend/optimization.js.map +1 -0
  218. package/dist/backend/optimization.test.d.ts +1 -0
  219. package/dist/backend/optimization.test.js +24 -0
  220. package/dist/backend/optimization.test.js.map +1 -0
  221. package/dist/backend/runtime-abi.d.ts +2 -2
  222. package/dist/backend/runtime-abi.js +2 -2
  223. package/dist/backend/runtime-pack-core.d.ts +16 -4
  224. package/dist/backend/runtime-pack-core.js +31 -13
  225. package/dist/backend/runtime-pack-core.js.map +1 -1
  226. package/dist/backend/runtime-pack-native.d.ts +7 -3
  227. package/dist/backend/runtime-pack-native.js +0 -3
  228. package/dist/backend/runtime-pack-native.js.map +1 -1
  229. package/dist/backend/runtime-pack-targets.test.js +41 -4
  230. package/dist/backend/runtime-pack-targets.test.js.map +1 -1
  231. package/dist/backend/runtime-pack.d.ts +20 -2
  232. package/dist/backend/runtime-pack.js +23 -0
  233. package/dist/backend/runtime-pack.js.map +1 -1
  234. package/dist/backend/runtime-pack.test.js +125 -2
  235. package/dist/backend/runtime-pack.test.js.map +1 -1
  236. package/dist/backend/target-diagnostics.test.js +1 -1
  237. package/dist/backend/targets.d.ts +2 -1
  238. package/dist/backend/targets.js +1 -1
  239. package/dist/backend/targets.js.map +1 -1
  240. package/dist/cli/command.js +5 -4
  241. package/dist/cli/command.js.map +1 -1
  242. package/dist/cli/host.d.ts +2 -1
  243. package/dist/cli/usage.d.ts +1 -1
  244. package/dist/cli/usage.js +5 -2
  245. package/dist/cli/usage.js.map +1 -1
  246. package/dist/compile-types.d.ts +5 -2
  247. package/dist/diagnostics/diagnostic.js +10 -8
  248. package/dist/diagnostics/diagnostic.js.map +1 -1
  249. package/dist/executable/executable-cache.d.ts +3 -2
  250. package/dist/executable/executable-cache.js +8 -4
  251. package/dist/executable/executable-cache.js.map +1 -1
  252. package/dist/executable/executable-cache.test.js +35 -0
  253. package/dist/executable/executable-cache.test.js.map +1 -1
  254. package/dist/frontend/fork-target.d.ts +5 -0
  255. package/dist/frontend/fork-target.js +40 -8
  256. package/dist/frontend/fork-target.js.map +1 -1
  257. package/dist/frontend/fork-target.test.d.ts +1 -0
  258. package/dist/frontend/fork-target.test.js +59 -0
  259. package/dist/frontend/fork-target.test.js.map +1 -0
  260. package/dist/frontend/lowering/abstract-equality.js +5 -49
  261. package/dist/frontend/lowering/abstract-equality.js.map +1 -1
  262. package/dist/frontend/lowering/array-values.d.ts +23 -0
  263. package/dist/frontend/lowering/array-values.js +129 -0
  264. package/dist/frontend/lowering/array-values.js.map +1 -1
  265. package/dist/frontend/lowering/binding-analysis.js +2 -2
  266. package/dist/frontend/lowering/binding-analysis.js.map +1 -1
  267. package/dist/frontend/lowering/builtins/atomics.d.ts +2 -11
  268. package/dist/frontend/lowering/builtins/atomics.js +64 -28
  269. package/dist/frontend/lowering/builtins/atomics.js.map +1 -1
  270. package/dist/frontend/lowering/builtins/errors.js +17 -2
  271. package/dist/frontend/lowering/builtins/errors.js.map +1 -1
  272. package/dist/frontend/lowering/builtins/filesystem-calls.d.ts +3 -0
  273. package/dist/frontend/lowering/builtins/filesystem-calls.js +51 -4
  274. package/dist/frontend/lowering/builtins/filesystem-calls.js.map +1 -1
  275. package/dist/frontend/lowering/builtins/module-calls.js +6 -1
  276. package/dist/frontend/lowering/builtins/module-calls.js.map +1 -1
  277. package/dist/frontend/lowering/builtins/process.d.ts +6 -17
  278. package/dist/frontend/lowering/builtins/process.js +56 -29
  279. package/dist/frontend/lowering/builtins/process.js.map +1 -1
  280. package/dist/frontend/lowering/builtins/workers.d.ts +5 -0
  281. package/dist/frontend/lowering/builtins/workers.js +65 -0
  282. package/dist/frontend/lowering/builtins/workers.js.map +1 -0
  283. package/dist/frontend/lowering/caught-value-dispatch.d.ts +11 -0
  284. package/dist/frontend/lowering/caught-value-dispatch.js +87 -0
  285. package/dist/frontend/lowering/caught-value-dispatch.js.map +1 -0
  286. package/dist/frontend/lowering/class-assertions.d.ts +11 -0
  287. package/dist/frontend/lowering/class-assertions.js +104 -0
  288. package/dist/frontend/lowering/class-assertions.js.map +1 -0
  289. package/dist/frontend/lowering/class-callbacks.d.ts +3 -3
  290. package/dist/frontend/lowering/class-callbacks.js +18 -5
  291. package/dist/frontend/lowering/class-callbacks.js.map +1 -1
  292. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +1 -0
  293. package/dist/frontend/lowering/class-dynamic-dispatch.js +4 -1
  294. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  295. package/dist/frontend/lowering/class-method-mutations.d.ts +5 -0
  296. package/dist/frontend/lowering/class-method-mutations.js +472 -0
  297. package/dist/frontend/lowering/class-method-mutations.js.map +1 -0
  298. package/dist/frontend/lowering/class-method-values.js +25 -5
  299. package/dist/frontend/lowering/class-method-values.js.map +1 -1
  300. package/dist/frontend/lowering/class-protocols.d.ts +17 -0
  301. package/dist/frontend/lowering/class-protocols.js +126 -0
  302. package/dist/frontend/lowering/class-protocols.js.map +1 -0
  303. package/dist/frontend/lowering/class-prototypes.js +8 -2
  304. package/dist/frontend/lowering/class-prototypes.js.map +1 -1
  305. package/dist/frontend/lowering/class-unions.d.ts +16 -0
  306. package/dist/frontend/lowering/class-unions.js +127 -0
  307. package/dist/frontend/lowering/class-unions.js.map +1 -0
  308. package/dist/frontend/lowering/coercions/builders.js +8 -1
  309. package/dist/frontend/lowering/coercions/builders.js.map +1 -1
  310. package/dist/frontend/lowering/coercions/function-adapters.js +2 -0
  311. package/dist/frontend/lowering/coercions/function-adapters.js.map +1 -1
  312. package/dist/frontend/lowering/coercions/identity.d.ts +7 -0
  313. package/dist/frontend/lowering/coercions/identity.js +26 -0
  314. package/dist/frontend/lowering/coercions/identity.js.map +1 -0
  315. package/dist/frontend/lowering/coercions/structural.js +9 -6
  316. package/dist/frontend/lowering/coercions/structural.js.map +1 -1
  317. package/dist/frontend/lowering/collection-narrowing.d.ts +6 -0
  318. package/dist/frontend/lowering/collection-narrowing.js +31 -0
  319. package/dist/frontend/lowering/collection-narrowing.js.map +1 -0
  320. package/dist/frontend/lowering/containers/array-callback-call.d.ts +7 -0
  321. package/dist/frontend/lowering/containers/array-callback-call.js +52 -0
  322. package/dist/frontend/lowering/containers/array-callback-call.js.map +1 -0
  323. package/dist/frontend/lowering/containers/array-callbacks.d.ts +8 -12
  324. package/dist/frontend/lowering/containers/array-callbacks.js +415 -136
  325. package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
  326. package/dist/frontend/lowering/containers/array-concat.d.ts +7 -0
  327. package/dist/frontend/lowering/containers/array-concat.js +130 -0
  328. package/dist/frontend/lowering/containers/array-concat.js.map +1 -0
  329. package/dist/frontend/lowering/containers/array-construction.d.ts +2 -0
  330. package/dist/frontend/lowering/containers/array-construction.js +95 -3
  331. package/dist/frontend/lowering/containers/array-construction.js.map +1 -1
  332. package/dist/frontend/lowering/containers/array-methods.d.ts +1 -11
  333. package/dist/frontend/lowering/containers/array-methods.js +43 -132
  334. package/dist/frontend/lowering/containers/array-methods.js.map +1 -1
  335. package/dist/frontend/lowering/containers/bytes.js +12 -34
  336. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  337. package/dist/frontend/lowering/containers/collection-methods.js +10 -1
  338. package/dist/frontend/lowering/containers/collection-methods.js.map +1 -1
  339. package/dist/frontend/lowering/containers/indexed-objects.js +56 -70
  340. package/dist/frontend/lowering/containers/indexed-objects.js.map +1 -1
  341. package/dist/frontend/lowering/containers/string-and-regexp.js +22 -3
  342. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  343. package/dist/frontend/lowering/cycle-initialization.d.ts +41 -0
  344. package/dist/frontend/lowering/cycle-initialization.js +277 -0
  345. package/dist/frontend/lowering/cycle-initialization.js.map +1 -0
  346. package/dist/frontend/lowering/expressions/evaluation-safety.js +4 -0
  347. package/dist/frontend/lowering/expressions/evaluation-safety.js.map +1 -1
  348. package/dist/frontend/lowering/expressions/object-literals.js +140 -38
  349. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  350. package/dist/frontend/lowering/expressions/union-field-write.d.ts +4 -4
  351. package/dist/frontend/lowering/expressions/union-field-write.js +54 -44
  352. package/dist/frontend/lowering/expressions/union-field-write.js.map +1 -1
  353. package/dist/frontend/lowering/generic-functions.d.ts +2 -5
  354. package/dist/frontend/lowering/generic-functions.js +13 -10
  355. package/dist/frontend/lowering/generic-functions.js.map +1 -1
  356. package/dist/frontend/lowering/instantiation-path.d.ts +8 -0
  357. package/dist/frontend/lowering/instantiation-path.js +10 -0
  358. package/dist/frontend/lowering/instantiation-path.js.map +1 -0
  359. package/dist/frontend/lowering/instantiation-path.test.d.ts +1 -0
  360. package/dist/frontend/lowering/instantiation-path.test.js +23 -0
  361. package/dist/frontend/lowering/instantiation-path.test.js.map +1 -0
  362. package/dist/frontend/lowering/iterator-adapters.d.ts +20 -0
  363. package/dist/frontend/lowering/iterator-adapters.js +605 -0
  364. package/dist/frontend/lowering/iterator-adapters.js.map +1 -0
  365. package/dist/frontend/lowering/lower-array-sort.d.ts +1 -1
  366. package/dist/frontend/lowering/lower-array-sort.js +44 -5
  367. package/dist/frontend/lowering/lower-array-sort.js.map +1 -1
  368. package/dist/frontend/lowering/lower-array-sort.test.d.ts +1 -0
  369. package/dist/frontend/lowering/lower-array-sort.test.js +31 -0
  370. package/dist/frontend/lowering/lower-array-sort.test.js.map +1 -0
  371. package/dist/frontend/lowering/lower-assert.js +7 -0
  372. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  373. package/dist/frontend/lowering/lower-builtin-values.js +12 -7
  374. package/dist/frontend/lowering/lower-builtin-values.js.map +1 -1
  375. package/dist/frontend/lowering/lower-calls.d.ts +3 -3
  376. package/dist/frontend/lowering/lower-calls.js +198 -124
  377. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  378. package/dist/frontend/lowering/lower-classes.d.ts +7 -0
  379. package/dist/frontend/lowering/lower-classes.js +166 -96
  380. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  381. package/dist/frontend/lowering/lower-event-emitter.js +1 -1
  382. package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
  383. package/dist/frontend/lowering/lower-exprs.d.ts +9 -2
  384. package/dist/frontend/lowering/lower-exprs.js +421 -167
  385. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  386. package/dist/frontend/lowering/lower-functions.d.ts +1 -1
  387. package/dist/frontend/lowering/lower-functions.js +33 -20
  388. package/dist/frontend/lowering/lower-functions.js.map +1 -1
  389. package/dist/frontend/lowering/lower-inspect.js +26 -2
  390. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  391. package/dist/frontend/lowering/lower-island.js +1 -1
  392. package/dist/frontend/lowering/lower-island.js.map +1 -1
  393. package/dist/frontend/lowering/lower-modules.d.ts +1 -0
  394. package/dist/frontend/lowering/lower-modules.js +54 -11
  395. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  396. package/dist/frontend/lowering/lower-stmts.js +59 -69
  397. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  398. package/dist/frontend/lowering/lower-stream.js +1 -1
  399. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  400. package/dist/frontend/lowering/lowerer.d.ts +50 -1
  401. package/dist/frontend/lowering/lowerer.js +333 -26
  402. package/dist/frontend/lowering/lowerer.js.map +1 -1
  403. package/dist/frontend/lowering/native-ffi.js +3 -1
  404. package/dist/frontend/lowering/native-ffi.js.map +1 -1
  405. package/dist/frontend/lowering/runtime-optional-provenance.d.ts +15 -0
  406. package/dist/frontend/lowering/runtime-optional-provenance.js +40 -0
  407. package/dist/frontend/lowering/runtime-optional-provenance.js.map +1 -0
  408. package/dist/frontend/lowering/sanitize-class-types.test.js +2 -2
  409. package/dist/frontend/lowering/split-consumers.d.ts +7 -0
  410. package/dist/frontend/lowering/split-consumers.js +64 -0
  411. package/dist/frontend/lowering/split-consumers.js.map +1 -0
  412. package/dist/frontend/lowering/strict-equality.d.ts +9 -0
  413. package/dist/frontend/lowering/strict-equality.js +116 -0
  414. package/dist/frontend/lowering/strict-equality.js.map +1 -0
  415. package/dist/frontend/lowering/surfaces.d.ts +3 -4
  416. package/dist/frontend/lowering/surfaces.js +38 -7
  417. package/dist/frontend/lowering/surfaces.js.map +1 -1
  418. package/dist/frontend/lowering/union-comparison.d.ts +5 -0
  419. package/dist/frontend/lowering/union-comparison.js +47 -0
  420. package/dist/frontend/lowering/union-comparison.js.map +1 -0
  421. package/dist/frontend/module-source-candidates.d.ts +10 -0
  422. package/dist/frontend/module-source-candidates.js +40 -0
  423. package/dist/frontend/module-source-candidates.js.map +1 -0
  424. package/dist/frontend/module-source-candidates.test.d.ts +1 -0
  425. package/dist/frontend/module-source-candidates.test.js +53 -0
  426. package/dist/frontend/module-source-candidates.test.js.map +1 -0
  427. package/dist/frontend/pipeline.js +2 -2
  428. package/dist/frontend/pipeline.js.map +1 -1
  429. package/dist/frontend/program-analysis.d.ts +2 -0
  430. package/dist/frontend/program-analysis.js +2 -0
  431. package/dist/frontend/program-analysis.js.map +1 -1
  432. package/dist/frontend/program.d.ts +38 -2
  433. package/dist/frontend/program.js +457 -88
  434. package/dist/frontend/program.js.map +1 -1
  435. package/dist/frontend/program.test.js +59 -6
  436. package/dist/frontend/program.test.js.map +1 -1
  437. package/dist/frontend/ts7/ast-node.js +6 -8
  438. package/dist/frontend/ts7/ast-node.js.map +1 -1
  439. package/dist/frontend/ts7/ast-node.test.js +42 -1
  440. package/dist/frontend/ts7/ast-node.test.js.map +1 -1
  441. package/dist/frontend/ts7/ast-wire.d.ts +4 -0
  442. package/dist/frontend/ts7/ast-wire.js +28 -0
  443. package/dist/frontend/ts7/ast-wire.js.map +1 -1
  444. package/dist/frontend/ts7/ast.d.ts +2 -1
  445. package/dist/frontend/ts7/ast.js +8 -4
  446. package/dist/frontend/ts7/ast.js.map +1 -1
  447. package/dist/frontend/ts7/checker.d.ts +8 -2
  448. package/dist/frontend/ts7/checker.js +41 -5
  449. package/dist/frontend/ts7/checker.js.map +1 -1
  450. package/dist/frontend/ts7/checker.test.js +42 -0
  451. package/dist/frontend/ts7/checker.test.js.map +1 -1
  452. package/dist/frontend/ts7/program-host.d.ts +7 -0
  453. package/dist/frontend/ts7/program-host.js +26 -2
  454. package/dist/frontend/ts7/program-host.js.map +1 -1
  455. package/dist/frontend/ts7/program-host.test.js +29 -0
  456. package/dist/frontend/ts7/program-host.test.js.map +1 -1
  457. package/dist/frontend/type-mapper.d.ts +4 -1
  458. package/dist/frontend/type-mapper.js +133 -16
  459. package/dist/frontend/type-mapper.js.map +1 -1
  460. package/dist/frontend/type-mapper.test.js +15 -3
  461. package/dist/frontend/type-mapper.test.js.map +1 -1
  462. package/dist/frontend/worker-target.d.ts +6 -0
  463. package/dist/frontend/worker-target.js +108 -0
  464. package/dist/frontend/worker-target.js.map +1 -0
  465. package/dist/frontend/worker-target.test.d.ts +1 -0
  466. package/dist/frontend/worker-target.test.js +71 -0
  467. package/dist/frontend/worker-target.test.js.map +1 -0
  468. package/dist/index.js +47 -14
  469. package/dist/index.js.map +1 -1
  470. package/dist/ir/analysis.d.ts +3 -1
  471. package/dist/ir/analysis.js +4 -0
  472. package/dist/ir/analysis.js.map +1 -1
  473. package/dist/ir/builtin-effects.js +12 -0
  474. package/dist/ir/builtin-effects.js.map +1 -1
  475. package/dist/ir/builtin-signatures.d.ts +1 -1
  476. package/dist/ir/builtin-signatures.js +15 -15
  477. package/dist/ir/builtin-signatures.js.map +1 -1
  478. package/dist/ir/constant-tables.test.js +1 -1
  479. package/dist/ir/initializer-bindings.test.js +1 -1
  480. package/dist/ir/ir.d.ts +85 -23
  481. package/dist/ir/ir.js +20 -6
  482. package/dist/ir/ir.js.map +1 -1
  483. package/dist/ir/numeric-call-specialization.d.ts +8 -0
  484. package/dist/ir/numeric-call-specialization.js +198 -0
  485. package/dist/ir/numeric-call-specialization.js.map +1 -0
  486. package/dist/ir/runtime-features.js +4 -3
  487. package/dist/ir/runtime-features.js.map +1 -1
  488. package/dist/ir/scalar-records.test.js +1 -1
  489. package/dist/ir/serialize.d.ts +1 -1
  490. package/dist/ir/serialize.js +3 -3
  491. package/dist/ir/serialize.js.map +1 -1
  492. package/dist/ir/traverse.js +8 -0
  493. package/dist/ir/traverse.js.map +1 -1
  494. package/dist/ir/validate.js +207 -43
  495. package/dist/ir/validate.js.map +1 -1
  496. package/dist/ir/validate.test.js +356 -8
  497. package/dist/ir/validate.test.js.map +1 -1
  498. package/dist/library/fence-eval.test.js +1 -1
  499. package/dist/library/int-infer.test.js +4 -4
  500. package/dist/library/ir-policy.js +2 -0
  501. package/dist/library/ir-policy.js.map +1 -1
  502. package/dist/library/library-cache.test.js +5 -5
  503. package/dist/library/library-profile.d.ts +2 -1
  504. package/dist/library/library-profile.js +4 -3
  505. package/dist/library/library-profile.js.map +1 -1
  506. package/dist/native/compiler.js +24 -11
  507. package/dist/native/compiler.js.map +1 -1
  508. package/dist/native/compiler.test.js +7 -3
  509. package/dist/native/compiler.test.js.map +1 -1
  510. package/dist/native/library.d.ts +2 -1
  511. package/dist/native/library.js.map +1 -1
  512. package/dist/native/prepare.js +29 -3
  513. package/dist/native/prepare.js.map +1 -1
  514. package/dist/native/sanitizer.d.ts +3 -2
  515. package/dist/native/sanitizer.js +3 -13
  516. package/dist/native/sanitizer.js.map +1 -1
  517. package/dist/native/sanitizer.test.js +1 -0
  518. package/dist/native/sanitizer.test.js.map +1 -1
  519. package/package.json +20 -20
  520. package/surface-manifest.json +37 -3
@@ -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";
@@ -9,6 +12,7 @@ import { typeKey } from "../../type-mapper.js";
9
12
  import { lowerArrayCallback, requireProducedArrayElement, callbackArrayElement, } from "./callback-arguments.js";
10
13
  import { reverseArrayLoop, arrayLengthDeclaration, arrayCallbackParams, arrayCallbackLocals, callArrayCallback, } from "./array-iteration.js";
11
14
  import { dynamicReceiverThrows } from "./dynamic-receivers.js";
15
+ import { defaultAfterUndefined, lowerStaticallyUndefinedArgument } from "../optional-arguments.js";
12
16
  /** `a.map(fn)` / `a.filter(fn)` / `a.forEach(fn)` desugar to a direct
13
17
  * call of a synthetic module function — one per method + element/result
14
18
  * type + callback-arity combination, interned — whose body is a plain
@@ -69,9 +73,19 @@ export function lowerArrayHofCall(lowerer, call, access, method, elem) {
69
73
  const outElem = method === "filter"
70
74
  ? filterResultElem(lowerer, call, argNode, elem, valueT, booleanFilter)
71
75
  : callbackArrayElement(lowerer, call, fnRet);
72
- 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);
73
81
  const resultType = method === "map" || method === "filter" ? arrayOf(outElem) : VOID;
74
- 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
+ };
75
89
  }
76
90
  /** The checker-selected element of a filter result, with the same trust
77
91
  * boundary as the historical narrowing filter: an inferred inline type
@@ -111,13 +125,15 @@ function filterResultElem(lowerer, call, argNode, elem, valueT, booleanFilter) {
111
125
  `unchecked assertion nothing validates at runtime — ${annotateEscape})`);
112
126
  }
113
127
  }
114
- 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)) {
115
131
  const multiArm = outElem.kind === "union";
116
132
  lowerer.unsupported("SC1090", call, `'.filter' narrowing '${lowerer.fmt(elem)}' elements to ` +
117
133
  `${multiArm ? `the multi-arm '${lowerer.fmt(outElem)}'` : `'${lowerer.fmt(outElem)}'`} ` +
118
134
  `(${multiArm ? "only a SINGLE arm re-tags" : "only a single runtime arm re-tags"} — ${annotateEscape})`);
119
135
  }
120
- if (booleanFilter) {
136
+ if (booleanFilter && valueT.kind === "union") {
121
137
  const arms = lowerer.unions.get(valueT.unionId)?.arms ?? [];
122
138
  if (arms.some((arm) => !typeEquals(arm, outElem) && !isUnitType(arm))) {
123
139
  lowerer.unsupported("SC1090", call, `'.filter(Boolean)' narrowing '${lowerer.fmt(elem)}' to '${lowerer.fmt(outElem)}' ` +
@@ -193,18 +209,193 @@ function filterCond(call, fnRet, loc) {
193
209
  // the runtime's kind-aware ToBoolean.
194
210
  return { kind: "toBool", operand: call, type: BOOL, loc };
195
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
+ }
196
386
  /** Interned synthetic loop function for one (method, elem, fnRet, arity)
197
387
  * combo. Named `%arr.<method>.<n>` ('%' keeps it out of the user
198
388
  * namespace); rides `liftedFns` into the module like a lifted lambda (it
199
389
  * is a plain function — no captures). */
200
- function arrayHofHelper(lowerer, method, elem, fnRet, arity, loc, outElem = fnRet) {
201
- 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" : ""}`;
202
392
  const existing = lowerer.arrHofHelpers.get(key);
203
393
  if (existing)
204
394
  return existing;
205
395
  const name = `%arr.${method}.${lowerer.arrHofHelpers.size}`;
206
396
  lowerer.arrHofHelpers.set(key, name);
207
- 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);
208
399
  return name;
209
400
  }
210
401
  /** The TS 5.2+ callable-union array rule: a `T[] | U[]` receiver exposes
@@ -362,7 +553,7 @@ function arrayUnionHofHelper(lowerer, method, receiverT, arrays, callbackT, arit
362
553
  * `arity` is the callback's declared parameter count (1–3): the loop
363
554
  * passes the index and the receiver itself after the element when the
364
555
  * callback names them, exactly the arguments JS supplies. */
365
- function buildArrayHofFn(lowerer, name, method, elem, fnRet, arity, loc, outElem) {
556
+ function buildArrayHofFn(lowerer, name, method, elem, fnRet, arity, loc, outElem, fastT = null) {
366
557
  const arrT = arrayOf(elem);
367
558
  const valueT = arrayValueType(lowerer, elem);
368
559
  const fnT = funcOf([arrayValueType(lowerer, elem), F64, arrT].slice(0, arity), fnRet);
@@ -427,22 +618,111 @@ function buildArrayHofFn(lowerer, name, method, elem, fnRet, arity, loc, outElem
427
618
  { kind: "return", value: varRef("out.0", outT, loc), loc },
428
619
  ];
429
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
+ }
430
705
  else if (method === "filter") {
431
706
  const outT = arrayOf(outElem);
432
707
  locals.push({ id: "out.0", name: "out", type: outT, mutable: false }, { id: "v.0", name: "v", type: valueT, mutable: false });
433
708
  returnType = outT;
709
+ const classView = !typeEquals(outElem, elem) && outElem.kind === "object"
710
+ ? checkedClassAssertion(lowerer, varRef("v.0", valueT, loc), outElem, loc)
711
+ : null;
434
712
  const retained = typeEquals(outElem, elem)
435
713
  ? varRef("v.0", valueT, loc)
436
- : valueT.kind === "union"
437
- ? {
438
- kind: "unionNarrow",
439
- unionId: valueT.unionId,
440
- tag: lowerer.armTag(valueT.unionId, outElem),
441
- value: varRef("v.0", valueT, loc),
442
- type: outElem,
443
- loc,
444
- }
445
- : 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);
446
726
  body = [
447
727
  {
448
728
  kind: "varDecl",
@@ -538,13 +818,15 @@ export function lowerArrayFindLikeCall(lowerer, call, access, method, elem, bind
538
818
  method === "every" ||
539
819
  method === "findIndex" ||
540
820
  method === "findLastIndex") {
821
+ const fast = lowerFastCallback(lowerer, argNode, [arrayValueType(lowerer, elem)], 0, elem, arrT, { fnArg, arity }, bindUntyped);
822
+ const fastT = fast?.type ?? null;
541
823
  const helper = method === "findIndex" || method === "findLastIndex"
542
- ? findIndexHelper(lowerer, elem, fnRet, arity, last, loc)
543
- : 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);
544
826
  return {
545
827
  kind: "call",
546
828
  callee: helper,
547
- args: [receiver, fnArg],
829
+ args: [receiver, fnArg, ...(fast ? [fast] : [])],
548
830
  type: method === "findIndex" || method === "findLastIndex" ? F64 : BOOL,
549
831
  loc,
550
832
  };
@@ -580,10 +862,12 @@ export function lowerArrayFindLikeCall(lowerer, call, access, method, elem, bind
580
862
  lowerer.unsupported("SC1090", call, `'.${method}' result narrowing without a predicate over its element`);
581
863
  }
582
864
  retag = lowerer.narrowedRetagHelper(call, valueT.unionId, resultT.unionId, loc);
583
- if (retag === null)
865
+ const present = lowerer.stripUndefinedArm(resultT);
866
+ if (retag === null &&
867
+ !(present.kind === "object" && canAssertClassValue(lowerer, valueT, present)))
584
868
  lowerer.unsupported("SC1090", call, `'.${method}' narrowing to an incompatible result layout`);
585
869
  }
586
- 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));
587
871
  return { kind: "call", callee: helper, args: [receiver, fnArg], type: resultT, loc };
588
872
  }
589
873
  /** ToBoolean of a predicate result inside a synthesized HOF helper — the
@@ -602,9 +886,9 @@ function predicateToBoolean(e) {
602
886
  * for (i = 0; i < n; i++) { v = a[i]; if (f(v)) return <v as result arm>; }
603
887
  * return <undefined arm>;
604
888
  */
605
- function findHelper(lowerer, elem, resultT, undefTag, fnRet, arity, last, loc, retag) {
889
+ function findHelper(lowerer, elem, resultT, undefTag, fnRet, arity, last, loc, retag, site = "") {
606
890
  const method = last ? "findLast" : "find";
607
- const key = `${method}:${typeKey(elem)}:${typeKey(resultT)}:${typeKey(fnRet)}:${arity}`;
891
+ const key = `${method}:${typeKey(elem)}:${typeKey(resultT)}:${typeKey(fnRet)}:${arity}${site}`;
608
892
  const existing = lowerer.arrHofHelpers.get(key);
609
893
  if (existing)
610
894
  return existing;
@@ -614,8 +898,14 @@ function findHelper(lowerer, elem, resultT, undefTag, fnRet, arity, last, loc, r
614
898
  const fnT = funcOf([arrayValueType(lowerer, elem), F64, arrT].slice(0, arity), fnRet);
615
899
  const valueT = arrayValueType(lowerer, elem);
616
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;
617
907
  const found = retag === null
618
- ? lowerer.coerceToExpected(v, resultT)
908
+ ? lowerer.coerceToExpected(classView ?? v, resultT)
619
909
  : { kind: "call", callee: retag, args: [v], type: resultT, loc };
620
910
  const miss = {
621
911
  kind: "unionWrap",
@@ -667,9 +957,9 @@ function findHelper(lowerer, elem, resultT, undefTag, fnRet, arity, last, loc, r
667
957
  *
668
958
  * n = a.length; for (...) if (f(a[i], i, a)) return i; return -1;
669
959
  */
670
- function findIndexHelper(lowerer, elem, fnRet, arity, last, loc) {
960
+ function findIndexHelper(lowerer, elem, fnRet, arity, last, loc, site = "", fastT = null) {
671
961
  const method = last ? "findLastIndex" : "findIndex";
672
- const key = `${method}:${typeKey(elem)}:${typeKey(fnRet)}:${arity}`;
962
+ const key = `${method}:${typeKey(elem)}:${typeKey(fnRet)}:${arity}${site}${fastT ? ":split" : ""}`;
673
963
  const existing = lowerer.arrHofHelpers.get(key);
674
964
  if (existing)
675
965
  return existing;
@@ -694,14 +984,14 @@ function findIndexHelper(lowerer, elem, fnRet, arity, last, loc) {
694
984
  loop,
695
985
  { kind: "return", value: { kind: "numLit", value: -1, type: F64, loc }, loc },
696
986
  ];
697
- lowerer.liftedFns.push({
987
+ lowerer.liftedFns.push(withFastCallback({
698
988
  name,
699
989
  params: arrayCallbackParams(arrT, fnT),
700
990
  returnType: F64,
701
991
  locals: [...arrayCallbackLocals(arrT, fnT)],
702
992
  body,
703
993
  loc,
704
- });
994
+ }, fastT, elem));
705
995
  return name;
706
996
  }
707
997
  /** The some/every loops — short-circuit early returns, JS-exact:
@@ -709,8 +999,8 @@ function findIndexHelper(lowerer, elem, fnRet, arity, last, loc) {
709
999
  * some: n = a.length; for (...) if (f(a[i])) return true; return false;
710
1000
  * every: n = a.length; for (...) if (!f(a[i])) return false; return true;
711
1001
  */
712
- function someEveryHelper(lowerer, method, elem, fnRet, arity, loc) {
713
- 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" : ""}`;
714
1004
  const existing = lowerer.arrHofHelpers.get(key);
715
1005
  if (existing)
716
1006
  return existing;
@@ -742,14 +1032,14 @@ function someEveryHelper(lowerer, method, elem, fnRet, arity, loc) {
742
1032
  ]),
743
1033
  { kind: "return", value: boolLit(method !== "some", loc), loc },
744
1034
  ];
745
- lowerer.liftedFns.push({
1035
+ lowerer.liftedFns.push(withFastCallback({
746
1036
  name,
747
1037
  params: arrayCallbackParams(arrT, fnT),
748
1038
  returnType: BOOL,
749
1039
  locals: [...arrayCallbackLocals(arrT, fnT)],
750
1040
  body,
751
1041
  loc,
752
- });
1042
+ }, fastT, elem));
753
1043
  return name;
754
1044
  }
755
1045
  /** `a.flatMap(f)` — map plus a one-level flatten. A callback returning
@@ -793,11 +1083,28 @@ export function lowerArrayFlatMapCall(lowerer, call, access, elem) {
793
1083
  lowerer.badType(call, lowerer.typeOf(call));
794
1084
  requireProducedArrayElement(lowerer, call, "'.flatMap()'", fnRet);
795
1085
  const outElem = callbackArrayElement(lowerer, call, fnRet);
796
- const helper = arrayHofHelper(lowerer, "flatMap", elem, fnRet, arity, loc, outElem);
797
- 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
+ };
798
1095
  }
799
- const helper = flatMapHelper(lowerer, elem, fnRet, arity, loc);
800
- 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
+ };
801
1108
  }
802
1109
  /** The flatMap loop (array-returning callback), from existing IR nodes:
803
1110
  *
@@ -808,8 +1115,8 @@ export function lowerArrayFlatMapCall(lowerer, call, access, elem) {
808
1115
  * }
809
1116
  * return out;
810
1117
  */
811
- function flatMapHelper(lowerer, elem, fnRet, arity, loc) {
812
- 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" : ""}`;
813
1120
  const existing = lowerer.arrHofHelpers.get(key);
814
1121
  if (existing)
815
1122
  return existing;
@@ -908,7 +1215,7 @@ function flatMapHelper(lowerer, elem, fnRet, arity, loc) {
908
1215
  ]),
909
1216
  { kind: "return", value: varRef("out.0", fnRet, loc), loc },
910
1217
  ];
911
- lowerer.liftedFns.push({
1218
+ lowerer.liftedFns.push(withFastCallback({
912
1219
  name,
913
1220
  params: arrayCallbackParams(arrT, fnT),
914
1221
  returnType: fnRet,
@@ -922,7 +1229,7 @@ function flatMapHelper(lowerer, elem, fnRet, arity, loc) {
922
1229
  ],
923
1230
  body,
924
1231
  loc,
925
- });
1232
+ }, fastT, elem));
926
1233
  return name;
927
1234
  }
928
1235
  /** `a.reduce(f)` / `a.reduce(f, init)` and reduceRight — both declared
@@ -943,10 +1250,15 @@ export function lowerArrayReduceCall(lowerer, call, access, method, elem) {
943
1250
  if (accT.kind === "void" || accT.kind === "func")
944
1251
  lowerer.badType(call, lowerer.typeOf(call));
945
1252
  const { fnArg, arity } = lowerArrayCallback(lowerer, argNode, [accT, arrayValueType(lowerer, elem)], arrT, false, accT);
946
- 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);
947
1255
  const args = [receiver, fnArg];
948
1256
  if (hasInit)
949
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);
950
1262
  return { kind: "call", callee: helper, args, type: accT, loc };
951
1263
  }
952
1264
  /** The reduce/reduceRight loops, from existing IR nodes:
@@ -959,8 +1271,8 @@ export function lowerArrayReduceCall(lowerer, call, access, method, elem) {
959
1271
  * reduce walks 0→n-1, reduceRight n-1→0; the seed without an initial
960
1272
  * value is a[0] / a[n-1] and the loop starts one past it. The empty-array
961
1273
  * TypeError message is Node's, byte for byte. */
962
- function reduceHelper(lowerer, method, elem, accT, fnRet, arity, hasInit, loc) {
963
- 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" : ""}`;
964
1276
  const existing = lowerer.arrHofHelpers.get(key);
965
1277
  if (existing)
966
1278
  return existing;
@@ -1100,53 +1412,77 @@ function reduceHelper(lowerer, method, elem, accT, fnRet, arity, hasInit, loc) {
1100
1412
  loop,
1101
1413
  { kind: "return", value: varRef("acc.0", accT, loc), loc },
1102
1414
  ];
1103
- lowerer.liftedFns.push({ name, params, returnType: accT, locals, body, loc });
1415
+ lowerer.liftedFns.push(withFastCallback({ name, params, returnType: accT, locals, body, loc }, fastT, elem));
1104
1416
  return name;
1105
1417
  }
1106
1418
  /** `a.sort(cmp)` / `a.toSorted(cmp)`, desugared to an interned synthetic
1107
1419
  * function like the other array HOFs. sort mutates and returns the receiver;
1108
1420
  * toSorted takes its shallow snapshot INSIDE the helper, after the receiver
1109
1421
  * and comparator expressions have both been evaluated, then sorts and
1110
- * returns that copy without touching the receiver. The helper uses a stable
1111
- * bottom-up merge sort with an ordered-boundary check: ordered inputs use a
1112
- * linear number of comparator calls, but buffer movement remains O(n log n)
1113
- * even when every boundary is already ordered. During a merge, an element
1422
+ * returns that copy without touching the receiver. The helper merges stable
1423
+ * natural runs, reversing only strict descending runs and extending short
1424
+ * runs with insertion sort. Ordered boundaries skip merging. During a merge, an element
1114
1425
  * moves right only while cmp(left, right) > 0, so a NaN or 0 result keeps
1115
1426
  * the left element first. Undefined values sink without reaching the user
1116
1427
  * comparator. The callback sequence differs from V8's TimSort, so exact
1117
1428
  * order and count parity are not claimed; results agree for consistent
1118
- * comparators. The comparator-less form lowers for STRING elements only —
1119
- * JS's default converts every element to string and compares UTF-16 units,
1120
- * so the interned synthesized comparator selects the runtime's code-unit
1121
- * ordering rather than scriptc's documented code-point relational
1122
- * operators. For numbers that default is the notorious string sort
1123
- * ([10, 9, 1] → [1, 10, 9]), deliberately fenced toward an explicit
1124
- * comparator. */
1429
+ * comparators. Without a comparator, string, number and boolean arrays use
1430
+ * native stable ordering: their String conversions cannot call user code.
1431
+ * Strings compare UTF-16 units; numbers compare their decimal spellings
1432
+ * ([10, 9, 1] → [1, 10, 9]). Other element types still need a comparator. */
1125
1433
  export function lowerArraySortCall(lowerer, call, access, elem, arrT) {
1126
1434
  const loc = locOf(call);
1127
1435
  const method = access.name.text === "toSorted" ? "toSorted" : "sort";
1128
1436
  const copyFirst = method === "toSorted";
1129
- if (call.arguments.length === 0 && elem.kind === "string") {
1130
- const receiver = lowerer.lowerExpr(access.expression);
1131
- const cmp = defaultStringCmpHelper(lowerer, loc);
1132
- const fnT = funcOf([STRING, STRING], F64);
1133
- const key = `${method}:${typeKey(STRING)}:2`;
1134
- let helper = lowerer.arrHofHelpers.get(key);
1135
- if (!helper) {
1136
- helper = `%arr.${method}.${lowerer.arrHofHelpers.size}`;
1137
- lowerer.arrHofHelpers.set(key, helper);
1138
- lowerer.liftedFns.push(buildArraySortFn(helper, STRING, 2, copyFirst, null, loc));
1139
- }
1140
- const fnArg = { kind: "closure", fnName: cmp, captures: [], type: fnT, loc };
1141
- return { kind: "call", callee: helper, args: [receiver, fnArg], type: arrT, loc };
1437
+ if (call.arguments.length === 0 &&
1438
+ (elem.kind === "string" || elem.kind === "f64" || elem.kind === "bool")) {
1439
+ return {
1440
+ kind: "arrIntrinsic",
1441
+ method: copyFirst ? "toSortedPrimitive" : "sortPrimitive",
1442
+ receiver: lowerer.lowerExpr(access.expression),
1443
+ args: [],
1444
+ type: arrT,
1445
+ loc,
1446
+ };
1142
1447
  }
1143
1448
  if (call.arguments.length !== 1) {
1144
- lowerer.noLowering(`.${method} with ${call.arguments.length} arguments`, call, "the default string-conversion ordering lowers only for string[] — pass a comparator: " +
1145
- `${method}((a, b) => a - b) for numbers`);
1449
+ lowerer.noLowering(`.${method} with ${call.arguments.length} arguments`, call, "default ordering supports string[], number[] and boolean[]; other element types need a comparator");
1146
1450
  }
1147
1451
  const receiver = lowerer.lowerExpr(access.expression);
1148
1452
  const argNode = call.arguments[0];
1149
- let fnArg = lowerer.lowerExpr(argNode);
1453
+ const undefinedArg = lowerStaticallyUndefinedArgument(lowerer, argNode);
1454
+ let unwrappedArg = argNode;
1455
+ while (ts.isParenthesizedExpression(unwrappedArg) ||
1456
+ ts.isAsExpression(unwrappedArg) ||
1457
+ ts.isTypeAssertion(unwrappedArg) ||
1458
+ ts.isSatisfiesExpression(unwrappedArg))
1459
+ unwrappedArg = unwrappedArg.expression;
1460
+ if (undefinedArg?.type.kind === "void" && !ts.isVoidExpression(unwrappedArg)) {
1461
+ lowerer.noLowering(`.${method} with an erased comparator result`, argNode, "pass the comparator directly, or use void expression to explicitly select default ordering");
1462
+ }
1463
+ if (undefinedArg !== null &&
1464
+ (undefinedArg.type.kind === "undefinedT" || ts.isVoidExpression(unwrappedArg)) &&
1465
+ (elem.kind === "string" || elem.kind === "f64" || elem.kind === "bool")) {
1466
+ // A type assertion alone cannot turn a function value into undefined.
1467
+ // The explicit undefined expression can mutate or replace the receiver.
1468
+ // Keep its original value alive and run the argument before sorting.
1469
+ const saved = lowerer.declareHiddenLocal("%sortReceiver", arrT);
1470
+ return {
1471
+ kind: "seqExpr",
1472
+ stmts: [{ kind: "varDecl", localId: saved.id, init: receiver, loc }],
1473
+ result: defaultAfterUndefined(undefinedArg, {
1474
+ kind: "arrIntrinsic",
1475
+ method: copyFirst ? "toSortedPrimitive" : "sortPrimitive",
1476
+ receiver: varRef(saved.id, arrT, loc),
1477
+ args: [],
1478
+ type: arrT,
1479
+ loc,
1480
+ }),
1481
+ type: arrT,
1482
+ loc,
1483
+ };
1484
+ }
1485
+ let fnArg = undefinedArg ?? lowerer.lowerExpr(argNode);
1150
1486
  // Reusable JS comparators often accept checked values. Adapt the array's
1151
1487
  // element ABI just as other array callbacks do before sorting.
1152
1488
  if (fnArg.type.kind === "func" &&
@@ -1171,76 +1507,19 @@ export function lowerArraySortCall(lowerer, call, access, elem, arrT) {
1171
1507
  lowerer.badType(argNode, lowerer.typeOf(argNode));
1172
1508
  }
1173
1509
  const arity = fnArg.type.params.length;
1174
- 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" : ""}`;
1175
1514
  let helper = lowerer.arrHofHelpers.get(key);
1176
1515
  if (!helper) {
1177
1516
  helper = `%arr.${method}.${lowerer.arrHofHelpers.size}`;
1178
1517
  lowerer.arrHofHelpers.set(key, helper);
1179
1518
  const undefinedTag = elem.kind === "union" ? lowerer.armTag(elem.unionId, UNDEFINED_T) : -1;
1180
- 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));
1181
1520
  }
1182
1521
  return { kind: "call", callee: helper, args: [receiver, fnArg], type: arrT, loc };
1183
1522
  }
1184
- /** JS's default sort comparator for STRING elements, interned once:
1185
- *
1186
- * (a, b) => a < b ? -1 : a > b ? 1 : 0
1187
- *
1188
- * The dedicated UTF-16 comparison flag keeps this exact across
1189
- * supplementary-plane code points and U+E000..U+FFFF, where the runtime's
1190
- * ordinary code-point relational order deliberately differs. */
1191
- function defaultStringCmpHelper(lowerer, loc) {
1192
- const key = "sortCmpStr";
1193
- const existing = lowerer.arrHofHelpers.get(key);
1194
- if (existing)
1195
- return existing;
1196
- const name = `%arr.sortCmpStr`;
1197
- lowerer.arrHofHelpers.set(key, name);
1198
- const cmp = (op) => ({
1199
- kind: "strCmp",
1200
- op,
1201
- left: varRef("a.0", STRING, loc),
1202
- right: varRef("b.0", STRING, loc),
1203
- utf16: true,
1204
- type: BOOL,
1205
- loc,
1206
- });
1207
- const body = [
1208
- {
1209
- kind: "return",
1210
- value: {
1211
- kind: "ternary",
1212
- cond: cmp("<"),
1213
- then: numLit(-1, loc),
1214
- else_: {
1215
- kind: "ternary",
1216
- cond: cmp(">"),
1217
- then: numLit(1, loc),
1218
- else_: numLit(0, loc),
1219
- type: F64,
1220
- loc,
1221
- },
1222
- type: F64,
1223
- loc,
1224
- },
1225
- loc,
1226
- },
1227
- ];
1228
- lowerer.liftedFns.push({
1229
- name,
1230
- params: [
1231
- { localId: "a.0", name: "a", type: STRING },
1232
- { localId: "b.0", name: "b", type: STRING },
1233
- ],
1234
- returnType: F64,
1235
- locals: [
1236
- { id: "a.0", name: "a", type: STRING, mutable: true },
1237
- { id: "b.0", name: "b", type: STRING, mutable: true },
1238
- ],
1239
- body,
1240
- loc,
1241
- });
1242
- return name;
1243
- }
1244
1523
  /** `d.filter(pred)` on a dyn receiver: the receiver must BE a dyn array
1245
1524
  * (else the Node-shaped TypeError above); the predicate runs per element
1246
1525
  * over the dyn value, and each SURVIVOR is validated-extracted into the