@scriptc/compiler 0.4.7 → 0.4.8

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 (776) hide show
  1. package/ambient/node-fallback/child_process.d.ts +71 -22
  2. package/ambient/node-fallback/crypto.d.ts +15 -7
  3. package/ambient/node-fallback/events.d.ts +23 -5
  4. package/ambient/node-fallback/fs.d.ts +3 -2
  5. package/ambient/node-fallback/http.d.ts +23 -17
  6. package/ambient/node-fallback/https.d.ts +5 -2
  7. package/ambient/node-fallback/net.d.ts +6 -0
  8. package/ambient/node-fallback/os.d.ts +11 -1
  9. package/ambient/node-fallback/path-posix.d.ts +6 -0
  10. package/ambient/node-fallback/path-win32.d.ts +5 -0
  11. package/ambient/node-fallback/path.d.ts +2 -0
  12. package/ambient/node-fallback/zlib.d.ts +31 -2
  13. package/ambient/scriptc-node-fallback.d.ts +37 -7
  14. package/ambient/scriptc.d.ts +7 -2
  15. package/dist/backend/executable-features.js +11 -3
  16. package/dist/backend/executable-features.js.map +1 -1
  17. package/dist/backend/library-pack.d.ts +6 -0
  18. package/dist/backend/library-pack.js +17 -6
  19. package/dist/backend/library-pack.js.map +1 -1
  20. package/dist/backend/library-pack.test.d.ts +1 -0
  21. package/dist/backend/library-pack.test.js +28 -0
  22. package/dist/backend/library-pack.test.js.map +1 -0
  23. package/dist/backend/linker.d.ts +9 -2
  24. package/dist/backend/linker.js +190 -32
  25. package/dist/backend/linker.js.map +1 -1
  26. package/dist/backend/lld.d.ts +8 -4
  27. package/dist/backend/lld.js +19 -13
  28. package/dist/backend/lld.js.map +1 -1
  29. package/dist/backend/lld.test.js +3 -1
  30. package/dist/backend/lld.test.js.map +1 -1
  31. package/dist/backend/llvm/alloc.d.ts +15 -2
  32. package/dist/backend/llvm/alloc.js +172 -36
  33. package/dist/backend/llvm/alloc.js.map +1 -1
  34. package/dist/backend/llvm/alloc.test.js +69 -1
  35. package/dist/backend/llvm/alloc.test.js.map +1 -1
  36. package/dist/backend/llvm/arenas.d.ts +17 -4
  37. package/dist/backend/llvm/arenas.js +105 -10
  38. package/dist/backend/llvm/arenas.js.map +1 -1
  39. package/dist/backend/llvm/arenas.test.js +229 -0
  40. package/dist/backend/llvm/arenas.test.js.map +1 -1
  41. package/dist/backend/llvm/bytes-alias.js +10 -1
  42. package/dist/backend/llvm/bytes-alias.js.map +1 -1
  43. package/dist/backend/llvm/bytes-headers.js +6 -0
  44. package/dist/backend/llvm/bytes-headers.js.map +1 -1
  45. package/dist/backend/llvm/bytes-loop-versions.test.js +25 -0
  46. package/dist/backend/llvm/bytes-loop-versions.test.js.map +1 -1
  47. package/dist/backend/llvm/call-lifetimes.js +10 -0
  48. package/dist/backend/llvm/call-lifetimes.js.map +1 -1
  49. package/dist/backend/llvm/classes.d.ts +16 -9
  50. package/dist/backend/llvm/classes.js +142 -37
  51. package/dist/backend/llvm/classes.js.map +1 -1
  52. package/dist/backend/llvm/classes.test.js +42 -0
  53. package/dist/backend/llvm/classes.test.js.map +1 -1
  54. package/dist/backend/llvm/cpu-dispatch.d.ts +15 -5
  55. package/dist/backend/llvm/cpu-dispatch.js +31 -7
  56. package/dist/backend/llvm/cpu-dispatch.js.map +1 -1
  57. package/dist/backend/llvm/dyn.d.ts +12 -3
  58. package/dist/backend/llvm/dyn.js +31 -7
  59. package/dist/backend/llvm/dyn.js.map +1 -1
  60. package/dist/backend/llvm/emit-function.js +67 -4
  61. package/dist/backend/llvm/emit-function.js.map +1 -1
  62. package/dist/backend/llvm/emit-module.js +90 -39
  63. package/dist/backend/llvm/emit-module.js.map +1 -1
  64. package/dist/backend/llvm/emit-module.test.d.ts +1 -0
  65. package/dist/backend/llvm/emit-module.test.js +52 -0
  66. package/dist/backend/llvm/emit-module.test.js.map +1 -0
  67. package/dist/backend/llvm/emit-statements.js +99 -15
  68. package/dist/backend/llvm/emit-statements.js.map +1 -1
  69. package/dist/backend/llvm/emitter.d.ts +113 -8
  70. package/dist/backend/llvm/emitter.js +438 -67
  71. package/dist/backend/llvm/emitter.js.map +1 -1
  72. package/dist/backend/llvm/emitter.test.js +31 -3
  73. package/dist/backend/llvm/emitter.test.js.map +1 -1
  74. package/dist/backend/llvm/expr-async.js +19 -1
  75. package/dist/backend/llvm/expr-async.js.map +1 -1
  76. package/dist/backend/llvm/expr-bytes.js +16 -1
  77. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  78. package/dist/backend/llvm/expr-calls.js +18 -2
  79. package/dist/backend/llvm/expr-calls.js.map +1 -1
  80. package/dist/backend/llvm/expr-dynamic.js +31 -10
  81. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  82. package/dist/backend/llvm/expr-primitives.js +31 -3
  83. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  84. package/dist/backend/llvm/expr-records.d.ts +1 -1
  85. package/dist/backend/llvm/expr-records.js +124 -56
  86. package/dist/backend/llvm/expr-records.js.map +1 -1
  87. package/dist/backend/llvm/expr-stream-bridges.js +17 -0
  88. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  89. package/dist/backend/llvm/js-groups.d.ts +21 -0
  90. package/dist/backend/llvm/js-groups.js +277 -0
  91. package/dist/backend/llvm/js-groups.js.map +1 -0
  92. package/dist/backend/llvm/js-ic.d.ts +19 -1
  93. package/dist/backend/llvm/js-ic.js +96 -23
  94. package/dist/backend/llvm/js-ic.js.map +1 -1
  95. package/dist/backend/llvm/lib-dispatch.js +132 -1
  96. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  97. package/dist/backend/llvm/lib-network.js +33 -6
  98. package/dist/backend/llvm/lib-network.js.map +1 -1
  99. package/dist/backend/llvm/lib-process.js +44 -3
  100. package/dist/backend/llvm/lib-process.js.map +1 -1
  101. package/dist/backend/llvm/lib-shared.js +69 -2
  102. package/dist/backend/llvm/lib-shared.js.map +1 -1
  103. package/dist/backend/llvm/local-union-storage.test.js +32 -0
  104. package/dist/backend/llvm/local-union-storage.test.js.map +1 -1
  105. package/dist/backend/llvm/loop-state.js +7 -2
  106. package/dist/backend/llvm/loop-state.js.map +1 -1
  107. package/dist/backend/llvm/map-entry-fusion.d.ts +8 -0
  108. package/dist/backend/llvm/map-entry-fusion.js +3 -3
  109. package/dist/backend/llvm/map-entry-fusion.js.map +1 -1
  110. package/dist/backend/llvm/map-number-lookup.test.js +6 -6
  111. package/dist/backend/llvm/map-number-lookup.test.js.map +1 -1
  112. package/dist/backend/llvm/nullable-unions.js +7 -6
  113. package/dist/backend/llvm/nullable-unions.js.map +1 -1
  114. package/dist/backend/llvm/nullable-unions.test.js +4 -1
  115. package/dist/backend/llvm/nullable-unions.test.js.map +1 -1
  116. package/dist/backend/llvm/receivers.js +3 -0
  117. package/dist/backend/llvm/receivers.js.map +1 -1
  118. package/dist/backend/llvm/record-entry-fusion.d.ts +32 -0
  119. package/dist/backend/llvm/record-entry-fusion.js +217 -0
  120. package/dist/backend/llvm/record-entry-fusion.js.map +1 -0
  121. package/dist/backend/llvm/record-results.d.ts +5 -2
  122. package/dist/backend/llvm/record-results.js +13 -12
  123. package/dist/backend/llvm/record-results.js.map +1 -1
  124. package/dist/backend/llvm/record-views.js +12 -6
  125. package/dist/backend/llvm/record-views.js.map +1 -1
  126. package/dist/backend/llvm/reference-effects.js +1 -0
  127. package/dist/backend/llvm/reference-effects.js.map +1 -1
  128. package/dist/backend/llvm/reference-writes.js +3 -0
  129. package/dist/backend/llvm/reference-writes.js.map +1 -1
  130. package/dist/backend/llvm/region-ir.js +1 -0
  131. package/dist/backend/llvm/region-ir.js.map +1 -1
  132. package/dist/backend/llvm/region-sites.d.ts +18 -0
  133. package/dist/backend/llvm/region-sites.js +79 -1
  134. package/dist/backend/llvm/region-sites.js.map +1 -1
  135. package/dist/backend/llvm/runtime-registries.test.js +53 -6
  136. package/dist/backend/llvm/runtime-registries.test.js.map +1 -1
  137. package/dist/backend/llvm/serialized-ir-emission.test.js +3 -1
  138. package/dist/backend/llvm/serialized-ir-emission.test.js.map +1 -1
  139. package/dist/backend/llvm/shapes.d.ts +33 -3
  140. package/dist/backend/llvm/shapes.js +183 -13
  141. package/dist/backend/llvm/shapes.js.map +1 -1
  142. package/dist/backend/llvm/stack-objects.d.ts +1 -2
  143. package/dist/backend/llvm/stack-objects.js +8 -5
  144. package/dist/backend/llvm/stack-objects.js.map +1 -1
  145. package/dist/backend/llvm/walkers.d.ts +12 -0
  146. package/dist/backend/llvm/walkers.js +46 -2
  147. package/dist/backend/llvm/walkers.js.map +1 -1
  148. package/dist/backend/may-throw.js +12 -2
  149. package/dist/backend/may-throw.js.map +1 -1
  150. package/dist/backend/may-throw.test.js +13 -0
  151. package/dist/backend/may-throw.test.js.map +1 -1
  152. package/dist/backend/native/contracts.d.ts +48 -8
  153. package/dist/backend/native/executable.js +55 -13
  154. package/dist/backend/native/executable.js.map +1 -1
  155. package/dist/backend/native/helper-identity-record.d.ts +11 -0
  156. package/dist/backend/native/helper-identity-record.js +76 -0
  157. package/dist/backend/native/helper-identity-record.js.map +1 -0
  158. package/dist/backend/native/helper-identity-record.test.d.ts +1 -0
  159. package/dist/backend/native/helper-identity-record.test.js +101 -0
  160. package/dist/backend/native/helper-identity-record.test.js.map +1 -0
  161. package/dist/backend/native/library.js +9 -1
  162. package/dist/backend/native/library.js.map +1 -1
  163. package/dist/backend/native/runtime-inputs.js +4 -1
  164. package/dist/backend/native/runtime-inputs.js.map +1 -1
  165. package/dist/backend/native/vendor.d.ts +1 -1
  166. package/dist/backend/native/vendor.js +1 -1
  167. package/dist/backend/native/vendor.js.map +1 -1
  168. package/dist/backend/native-codegen-core.d.ts +13 -10
  169. package/dist/backend/native-codegen-core.js +26 -13
  170. package/dist/backend/native-codegen-core.js.map +1 -1
  171. package/dist/backend/native-codegen.js +27 -8
  172. package/dist/backend/native-codegen.js.map +1 -1
  173. package/dist/backend/native-codegen.test.js +110 -14
  174. package/dist/backend/native-codegen.test.js.map +1 -1
  175. package/dist/backend/native-link-info-core.d.ts +37 -8
  176. package/dist/backend/native-link-info-core.js.map +1 -1
  177. package/dist/backend/runtime-pack-core.d.ts +17 -2
  178. package/dist/backend/runtime-pack-core.js +18 -3
  179. package/dist/backend/runtime-pack-core.js.map +1 -1
  180. package/dist/backend/runtime-pack-targets.test.js +1 -1
  181. package/dist/backend/runtime-pack-targets.test.js.map +1 -1
  182. package/dist/backend/runtime-pack.test.js +211 -2
  183. package/dist/backend/runtime-pack.test.js.map +1 -1
  184. package/dist/backend/tree-classes.d.ts +42 -0
  185. package/dist/backend/tree-classes.js +723 -0
  186. package/dist/backend/tree-classes.js.map +1 -0
  187. package/dist/backend/tree-classes.test.d.ts +1 -0
  188. package/dist/backend/tree-classes.test.js +338 -0
  189. package/dist/backend/tree-classes.test.js.map +1 -0
  190. package/dist/backend/vendor-archives.d.ts +5 -1
  191. package/dist/backend/vendor-archives.js +51 -7
  192. package/dist/backend/vendor-archives.js.map +1 -1
  193. package/dist/backend/vendor-inputs.d.ts +25 -4
  194. package/dist/backend/vendor-inputs.js +68 -4
  195. package/dist/backend/vendor-inputs.js.map +1 -1
  196. package/dist/backend/vendor-inputs.test.js +35 -1
  197. package/dist/backend/vendor-inputs.test.js.map +1 -1
  198. package/dist/backend/warm-cache.js +1 -1
  199. package/dist/backend/warm-cache.js.map +1 -1
  200. package/dist/compat/fetch-profile.js +2 -2
  201. package/dist/coverage/report.js +47 -0
  202. package/dist/coverage/report.js.map +1 -1
  203. package/dist/coverage/surface-manifest.js +1 -1
  204. package/dist/diagnostics/codes.d.ts +8 -0
  205. package/dist/diagnostics/codes.js +8 -0
  206. package/dist/diagnostics/codes.js.map +1 -1
  207. package/dist/diagnostics/diagnostic.d.ts +27 -9
  208. package/dist/diagnostics/diagnostic.js +60 -19
  209. package/dist/diagnostics/diagnostic.js.map +1 -1
  210. package/dist/diagnostics/envelope.d.ts +18 -0
  211. package/dist/diagnostics/envelope.js.map +1 -1
  212. package/dist/executable/executable-cache.d.ts +21 -2
  213. package/dist/executable/executable-cache.js +21 -1
  214. package/dist/executable/executable-cache.js.map +1 -1
  215. package/dist/executable/executable-cache.test.js +123 -1
  216. package/dist/executable/executable-cache.test.js.map +1 -1
  217. package/dist/executable/prepare.js +199 -248
  218. package/dist/executable/prepare.js.map +1 -1
  219. package/dist/frontend/analysis.js +200 -18
  220. package/dist/frontend/analysis.js.map +1 -1
  221. package/dist/frontend/builtin-modules.d.ts +4 -0
  222. package/dist/frontend/builtin-modules.js +10 -0
  223. package/dist/frontend/builtin-modules.js.map +1 -1
  224. package/dist/frontend/early-errors.d.ts +12 -2
  225. package/dist/frontend/early-errors.js +535 -4
  226. package/dist/frontend/early-errors.js.map +1 -1
  227. package/dist/frontend/early-errors.test.js +165 -0
  228. package/dist/frontend/early-errors.test.js.map +1 -1
  229. package/dist/frontend/inferred-js-diagnostics.test.js +65 -0
  230. package/dist/frontend/inferred-js-diagnostics.test.js.map +1 -1
  231. package/dist/frontend/jsx-opinion-sites.test.d.ts +1 -0
  232. package/dist/frontend/jsx-opinion-sites.test.js +86 -0
  233. package/dist/frontend/jsx-opinion-sites.test.js.map +1 -0
  234. package/dist/frontend/lib-exports.d.ts +23 -4
  235. package/dist/frontend/lib-exports.js +98 -26
  236. package/dist/frontend/lib-exports.js.map +1 -1
  237. package/dist/frontend/lowering/binding-analysis.js +21 -3
  238. package/dist/frontend/lowering/binding-analysis.js.map +1 -1
  239. package/dist/frontend/lowering/buffers.d.ts +8 -0
  240. package/dist/frontend/lowering/buffers.js +43 -0
  241. package/dist/frontend/lowering/buffers.js.map +1 -0
  242. package/dist/frontend/lowering/builtin-calls.js +4 -0
  243. package/dist/frontend/lowering/builtin-calls.js.map +1 -1
  244. package/dist/frontend/lowering/builtin-namespaces.d.ts +3 -2
  245. package/dist/frontend/lowering/builtin-namespaces.js +24 -3
  246. package/dist/frontend/lowering/builtin-namespaces.js.map +1 -1
  247. package/dist/frontend/lowering/builtin-statics.d.ts +24 -0
  248. package/dist/frontend/lowering/builtin-statics.js +407 -0
  249. package/dist/frontend/lowering/builtin-statics.js.map +1 -0
  250. package/dist/frontend/lowering/builtins/arguments.d.ts +4 -0
  251. package/dist/frontend/lowering/builtins/arguments.js +12 -0
  252. package/dist/frontend/lowering/builtins/arguments.js.map +1 -1
  253. package/dist/frontend/lowering/builtins/atomics.d.ts +6 -1
  254. package/dist/frontend/lowering/builtins/atomics.js +87 -1
  255. package/dist/frontend/lowering/builtins/atomics.js.map +1 -1
  256. package/dist/frontend/lowering/builtins/child-process-methods.js +2 -2
  257. package/dist/frontend/lowering/builtins/child-process-methods.js.map +1 -1
  258. package/dist/frontend/lowering/builtins/child-process-sync.d.ts +13 -0
  259. package/dist/frontend/lowering/builtins/child-process-sync.js +1 -13
  260. package/dist/frontend/lowering/builtins/child-process-sync.js.map +1 -1
  261. package/dist/frontend/lowering/builtins/child-process.d.ts +10 -4
  262. package/dist/frontend/lowering/builtins/child-process.js +560 -27
  263. package/dist/frontend/lowering/builtins/child-process.js.map +1 -1
  264. package/dist/frontend/lowering/builtins/compression.d.ts +2 -2
  265. package/dist/frontend/lowering/builtins/compression.js +41 -21
  266. package/dist/frontend/lowering/builtins/compression.js.map +1 -1
  267. package/dist/frontend/lowering/builtins/constants.js +7 -2
  268. package/dist/frontend/lowering/builtins/constants.js.map +1 -1
  269. package/dist/frontend/lowering/builtins/filesystem-calls.d.ts +1 -0
  270. package/dist/frontend/lowering/builtins/filesystem-calls.js +28 -2
  271. package/dist/frontend/lowering/builtins/filesystem-calls.js.map +1 -1
  272. package/dist/frontend/lowering/builtins/json.js +4 -0
  273. package/dist/frontend/lowering/builtins/json.js.map +1 -1
  274. package/dist/frontend/lowering/builtins/module-calls.js +3 -1
  275. package/dist/frontend/lowering/builtins/module-calls.js.map +1 -1
  276. package/dist/frontend/lowering/builtins/numbers.d.ts +4 -1
  277. package/dist/frontend/lowering/builtins/numbers.js +10 -2
  278. package/dist/frontend/lowering/builtins/numbers.js.map +1 -1
  279. package/dist/frontend/lowering/builtins/operating-system.d.ts +6 -3
  280. package/dist/frontend/lowering/builtins/operating-system.js +96 -16
  281. package/dist/frontend/lowering/builtins/operating-system.js.map +1 -1
  282. package/dist/frontend/lowering/builtins/process.d.ts +2 -2
  283. package/dist/frontend/lowering/builtins/process.js +103 -8
  284. package/dist/frontend/lowering/builtins/process.js.map +1 -1
  285. package/dist/frontend/lowering/builtins/promises.js +169 -8
  286. package/dist/frontend/lowering/builtins/promises.js.map +1 -1
  287. package/dist/frontend/lowering/builtins/properties.js +6 -2
  288. package/dist/frontend/lowering/builtins/properties.js.map +1 -1
  289. package/dist/frontend/lowering/builtins/readline.d.ts +6 -4
  290. package/dist/frontend/lowering/builtins/readline.js +180 -36
  291. package/dist/frontend/lowering/builtins/readline.js.map +1 -1
  292. package/dist/frontend/lowering/builtins/url.js +35 -12
  293. package/dist/frontend/lowering/builtins/url.js.map +1 -1
  294. package/dist/frontend/lowering/builtins/webassembly.js +2 -0
  295. package/dist/frontend/lowering/builtins/webassembly.js.map +1 -1
  296. package/dist/frontend/lowering/call-arguments.d.ts +10 -0
  297. package/dist/frontend/lowering/call-arguments.js +37 -2
  298. package/dist/frontend/lowering/call-arguments.js.map +1 -1
  299. package/dist/frontend/lowering/call-signatures.d.ts +10 -0
  300. package/dist/frontend/lowering/call-signatures.js +103 -0
  301. package/dist/frontend/lowering/call-signatures.js.map +1 -1
  302. package/dist/frontend/lowering/class-construction.d.ts +14 -2
  303. package/dist/frontend/lowering/class-construction.js +99 -5
  304. package/dist/frontend/lowering/class-construction.js.map +1 -1
  305. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +9 -0
  306. package/dist/frontend/lowering/class-dynamic-dispatch.js +1283 -1030
  307. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  308. package/dist/frontend/lowering/class-dynamic-dispatch.test.js +158 -0
  309. package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
  310. package/dist/frontend/lowering/class-prototypes.js +20 -15
  311. package/dist/frontend/lowering/class-prototypes.js.map +1 -1
  312. package/dist/frontend/lowering/class-runtime-statics.d.ts +8 -0
  313. package/dist/frontend/lowering/class-runtime-statics.js +20 -1
  314. package/dist/frontend/lowering/class-runtime-statics.js.map +1 -1
  315. package/dist/frontend/lowering/class-unions.js +21 -4
  316. package/dist/frontend/lowering/class-unions.js.map +1 -1
  317. package/dist/frontend/lowering/coercions/function-adapters.js +9 -0
  318. package/dist/frontend/lowering/coercions/function-adapters.js.map +1 -1
  319. package/dist/frontend/lowering/coercions/state.d.ts +8 -0
  320. package/dist/frontend/lowering/coercions/state.js +17 -0
  321. package/dist/frontend/lowering/coercions/state.js.map +1 -1
  322. package/dist/frontend/lowering/coercions/structural-plans.js +20 -5
  323. package/dist/frontend/lowering/coercions/structural-plans.js.map +1 -1
  324. package/dist/frontend/lowering/coercions/structural.js +10 -1
  325. package/dist/frontend/lowering/coercions/structural.js.map +1 -1
  326. package/dist/frontend/lowering/coercions/unions.d.ts +2 -1
  327. package/dist/frontend/lowering/coercions/unions.js +54 -10
  328. package/dist/frontend/lowering/coercions/unions.js.map +1 -1
  329. package/dist/frontend/lowering/constructor-returns.d.ts +23 -2
  330. package/dist/frontend/lowering/constructor-returns.js +284 -58
  331. package/dist/frontend/lowering/constructor-returns.js.map +1 -1
  332. package/dist/frontend/lowering/containers/array-callbacks.js +156 -62
  333. package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
  334. package/dist/frontend/lowering/containers/array-construction.js +21 -3
  335. package/dist/frontend/lowering/containers/array-construction.js.map +1 -1
  336. package/dist/frontend/lowering/containers/array-from-async.js +139 -3
  337. package/dist/frontend/lowering/containers/array-from-async.js.map +1 -1
  338. package/dist/frontend/lowering/containers/array-iteration.d.ts +14 -4
  339. package/dist/frontend/lowering/containers/array-iteration.js +24 -7
  340. package/dist/frontend/lowering/containers/array-iteration.js.map +1 -1
  341. package/dist/frontend/lowering/containers/array-methods.js +14 -11
  342. package/dist/frontend/lowering/containers/array-methods.js.map +1 -1
  343. package/dist/frontend/lowering/containers/bytes.d.ts +6 -0
  344. package/dist/frontend/lowering/containers/bytes.js +446 -86
  345. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  346. package/dist/frontend/lowering/containers/callback-arguments.d.ts +5 -0
  347. package/dist/frontend/lowering/containers/callback-arguments.js +21 -12
  348. package/dist/frontend/lowering/containers/callback-arguments.js.map +1 -1
  349. package/dist/frontend/lowering/containers/collection-grouping.js +421 -2
  350. package/dist/frontend/lowering/containers/collection-grouping.js.map +1 -1
  351. package/dist/frontend/lowering/containers/collection-methods.js +52 -17
  352. package/dist/frontend/lowering/containers/collection-methods.js.map +1 -1
  353. package/dist/frontend/lowering/containers/iterator-helpers.d.ts +23 -0
  354. package/dist/frontend/lowering/containers/iterator-helpers.js +176 -10
  355. package/dist/frontend/lowering/containers/iterator-helpers.js.map +1 -1
  356. package/dist/frontend/lowering/containers/string-and-regexp.d.ts +5 -2
  357. package/dist/frontend/lowering/containers/string-and-regexp.js +45 -11
  358. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  359. package/dist/frontend/lowering/crypto-tables.d.ts +3 -3
  360. package/dist/frontend/lowering/crypto-tables.js +5 -5
  361. package/dist/frontend/lowering/dispatch-sites.js +3 -0
  362. package/dist/frontend/lowering/dispatch-sites.js.map +1 -1
  363. package/dist/frontend/lowering/divergences.d.ts +40 -0
  364. package/dist/frontend/lowering/divergences.js +239 -20
  365. package/dist/frontend/lowering/divergences.js.map +1 -1
  366. package/dist/frontend/lowering/effect-free.d.ts +12 -0
  367. package/dist/frontend/lowering/effect-free.js +44 -0
  368. package/dist/frontend/lowering/effect-free.js.map +1 -0
  369. package/dist/frontend/lowering/expressions/array-literals.d.ts +10 -0
  370. package/dist/frontend/lowering/expressions/array-literals.js +62 -0
  371. package/dist/frontend/lowering/expressions/array-literals.js.map +1 -1
  372. package/dist/frontend/lowering/expressions/binary.js +115 -5
  373. package/dist/frontend/lowering/expressions/binary.js.map +1 -1
  374. package/dist/frontend/lowering/expressions/element-access.js +151 -7
  375. package/dist/frontend/lowering/expressions/element-access.js.map +1 -1
  376. package/dist/frontend/lowering/expressions/hosted-narrowing.d.ts +15 -0
  377. package/dist/frontend/lowering/expressions/hosted-narrowing.js +54 -1
  378. package/dist/frontend/lowering/expressions/hosted-narrowing.js.map +1 -1
  379. package/dist/frontend/lowering/expressions/identifiers.js +31 -2
  380. package/dist/frontend/lowering/expressions/identifiers.js.map +1 -1
  381. package/dist/frontend/lowering/expressions/narrowing.d.ts +3 -0
  382. package/dist/frontend/lowering/expressions/narrowing.js +175 -22
  383. package/dist/frontend/lowering/expressions/narrowing.js.map +1 -1
  384. package/dist/frontend/lowering/expressions/object-literals.js +173 -11
  385. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  386. package/dist/frontend/lowering/expressions/optional-chains.js +5 -1
  387. package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
  388. package/dist/frontend/lowering/expressions/property-access.d.ts +8 -0
  389. package/dist/frontend/lowering/expressions/property-access.js +379 -109
  390. package/dist/frontend/lowering/expressions/property-access.js.map +1 -1
  391. package/dist/frontend/lowering/expressions/relational.js +237 -7
  392. package/dist/frontend/lowering/expressions/relational.js.map +1 -1
  393. package/dist/frontend/lowering/expressions/typeof.js +8 -0
  394. package/dist/frontend/lowering/expressions/typeof.js.map +1 -1
  395. package/dist/frontend/lowering/expressions/union-fields.d.ts +20 -1
  396. package/dist/frontend/lowering/expressions/union-fields.js +103 -13
  397. package/dist/frontend/lowering/expressions/union-fields.js.map +1 -1
  398. package/dist/frontend/lowering/expressions/updates.js +74 -55
  399. package/dist/frontend/lowering/expressions/updates.js.map +1 -1
  400. package/dist/frontend/lowering/function-returns.js +37 -10
  401. package/dist/frontend/lowering/function-returns.js.map +1 -1
  402. package/dist/frontend/lowering/general-streams.js +5 -0
  403. package/dist/frontend/lowering/general-streams.js.map +1 -1
  404. package/dist/frontend/lowering/generator-delegation.d.ts +15 -7
  405. package/dist/frontend/lowering/generator-delegation.js +301 -118
  406. package/dist/frontend/lowering/generator-delegation.js.map +1 -1
  407. package/dist/frontend/lowering/generic-functions.d.ts +27 -1
  408. package/dist/frontend/lowering/generic-functions.js +432 -18
  409. package/dist/frontend/lowering/generic-functions.js.map +1 -1
  410. package/dist/frontend/lowering/global-function-values.d.ts +25 -0
  411. package/dist/frontend/lowering/global-function-values.js +193 -0
  412. package/dist/frontend/lowering/global-function-values.js.map +1 -0
  413. package/dist/frontend/lowering/global-values.d.ts +6 -4
  414. package/dist/frontend/lowering/global-values.js +24 -10
  415. package/dist/frontend/lowering/global-values.js.map +1 -1
  416. package/dist/frontend/lowering/host-global-values.d.ts +31 -0
  417. package/dist/frontend/lowering/host-global-values.js +121 -0
  418. package/dist/frontend/lowering/host-global-values.js.map +1 -0
  419. package/dist/frontend/lowering/host-globals.d.ts +74 -0
  420. package/dist/frontend/lowering/host-globals.js +344 -0
  421. package/dist/frontend/lowering/host-globals.js.map +1 -0
  422. package/dist/frontend/lowering/http2-constants.js +1 -1
  423. package/dist/frontend/lowering/iterator-adapters.js +46 -17
  424. package/dist/frontend/lowering/iterator-adapters.js.map +1 -1
  425. package/dist/frontend/lowering/iterator-prototype.d.ts +30 -0
  426. package/dist/frontend/lowering/iterator-prototype.js +160 -0
  427. package/dist/frontend/lowering/iterator-prototype.js.map +1 -0
  428. package/dist/frontend/lowering/key-order-witness.js +43 -22
  429. package/dist/frontend/lowering/key-order-witness.js.map +1 -1
  430. package/dist/frontend/lowering/key-order-witness.test.js +1 -0
  431. package/dist/frontend/lowering/key-order-witness.test.js.map +1 -1
  432. package/dist/frontend/lowering/lib-boundary.js +11 -3
  433. package/dist/frontend/lowering/lib-boundary.js.map +1 -1
  434. package/dist/frontend/lowering/lower-assert.js +30 -15
  435. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  436. package/dist/frontend/lowering/lower-async-iteration.d.ts +11 -0
  437. package/dist/frontend/lowering/lower-async-iteration.js +15 -0
  438. package/dist/frontend/lowering/lower-async-iteration.js.map +1 -1
  439. package/dist/frontend/lowering/lower-builtin-values.js +11 -1
  440. package/dist/frontend/lowering/lower-builtin-values.js.map +1 -1
  441. package/dist/frontend/lowering/lower-calls.d.ts +25 -0
  442. package/dist/frontend/lowering/lower-calls.js +929 -227
  443. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  444. package/dist/frontend/lowering/lower-calls.test.js +59 -16
  445. package/dist/frontend/lowering/lower-calls.test.js.map +1 -1
  446. package/dist/frontend/lowering/lower-classes.d.ts +20 -0
  447. package/dist/frontend/lowering/lower-classes.js +468 -44
  448. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  449. package/dist/frontend/lowering/lower-event-emitter.d.ts +6 -2
  450. package/dist/frontend/lowering/lower-event-emitter.js +253 -83
  451. package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
  452. package/dist/frontend/lowering/lower-exprs.d.ts +1 -1
  453. package/dist/frontend/lowering/lower-exprs.js +71 -20
  454. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  455. package/dist/frontend/lowering/lower-functions.js +25 -6
  456. package/dist/frontend/lowering/lower-functions.js.map +1 -1
  457. package/dist/frontend/lowering/lower-generators.js +57 -10
  458. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  459. package/dist/frontend/lowering/lower-global-value.d.ts +6 -0
  460. package/dist/frontend/lowering/lower-global-value.js +14 -5
  461. package/dist/frontend/lowering/lower-global-value.js.map +1 -1
  462. package/dist/frontend/lowering/lower-inspect.d.ts +4 -0
  463. package/dist/frontend/lowering/lower-inspect.js +638 -64
  464. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  465. package/dist/frontend/lowering/lower-modules.js +48 -2
  466. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  467. package/dist/frontend/lowering/lower-namespaces.js +18 -0
  468. package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
  469. package/dist/frontend/lowering/lower-node-island.js +16 -6
  470. package/dist/frontend/lowering/lower-node-island.js.map +1 -1
  471. package/dist/frontend/lowering/lower-server.js +303 -87
  472. package/dist/frontend/lowering/lower-server.js.map +1 -1
  473. package/dist/frontend/lowering/lower-stdlib.js +45 -0
  474. package/dist/frontend/lowering/lower-stdlib.js.map +1 -1
  475. package/dist/frontend/lowering/lower-stmts.d.ts +14 -11
  476. package/dist/frontend/lowering/lower-stmts.js +270 -52
  477. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  478. package/dist/frontend/lowering/lower-timers.js +110 -27
  479. package/dist/frontend/lowering/lower-timers.js.map +1 -1
  480. package/dist/frontend/lowering/lower-url.js +6 -3
  481. package/dist/frontend/lowering/lower-url.js.map +1 -1
  482. package/dist/frontend/lowering/lowerer.d.ts +227 -21
  483. package/dist/frontend/lowering/lowerer.js +651 -92
  484. package/dist/frontend/lowering/lowerer.js.map +1 -1
  485. package/dist/frontend/lowering/lowerer.test.js +18 -0
  486. package/dist/frontend/lowering/lowerer.test.js.map +1 -1
  487. package/dist/frontend/lowering/lowering-facts.d.ts +110 -0
  488. package/dist/frontend/lowering/lowering-facts.js +323 -0
  489. package/dist/frontend/lowering/lowering-facts.js.map +1 -0
  490. package/dist/frontend/lowering/lowering-facts.test.d.ts +1 -0
  491. package/dist/frontend/lowering/lowering-facts.test.js +100 -0
  492. package/dist/frontend/lowering/lowering-facts.test.js.map +1 -0
  493. package/dist/frontend/lowering/nan-coded-reads.d.ts +27 -4
  494. package/dist/frontend/lowering/nan-coded-reads.js +112 -9
  495. package/dist/frontend/lowering/nan-coded-reads.js.map +1 -1
  496. package/dist/frontend/lowering/optional-arguments.d.ts +4 -0
  497. package/dist/frontend/lowering/optional-arguments.js +26 -2
  498. package/dist/frontend/lowering/optional-arguments.js.map +1 -1
  499. package/dist/frontend/lowering/partial-assertions.d.ts +0 -3
  500. package/dist/frontend/lowering/partial-assertions.js +9 -15
  501. package/dist/frontend/lowering/partial-assertions.js.map +1 -1
  502. package/dist/frontend/lowering/primitive-throws.d.ts +100 -0
  503. package/dist/frontend/lowering/primitive-throws.js +241 -0
  504. package/dist/frontend/lowering/primitive-throws.js.map +1 -0
  505. package/dist/frontend/lowering/primitive-wrappers.js +1 -0
  506. package/dist/frontend/lowering/primitive-wrappers.js.map +1 -1
  507. package/dist/frontend/lowering/record-inherited.d.ts +17 -1
  508. package/dist/frontend/lowering/record-inherited.js +16 -2
  509. package/dist/frontend/lowering/record-inherited.js.map +1 -1
  510. package/dist/frontend/lowering/record-links.d.ts +73 -0
  511. package/dist/frontend/lowering/record-links.js +797 -0
  512. package/dist/frontend/lowering/record-links.js.map +1 -0
  513. package/dist/frontend/lowering/runtime-optional-provenance.d.ts +27 -7
  514. package/dist/frontend/lowering/runtime-optional-provenance.js +25 -11
  515. package/dist/frontend/lowering/runtime-optional-provenance.js.map +1 -1
  516. package/dist/frontend/lowering/runtime-optional-report.d.ts +40 -0
  517. package/dist/frontend/lowering/runtime-optional-report.js +300 -0
  518. package/dist/frontend/lowering/runtime-optional-report.js.map +1 -0
  519. package/dist/frontend/lowering/scoped-type-memo.test.d.ts +1 -0
  520. package/dist/frontend/lowering/scoped-type-memo.test.js +86 -0
  521. package/dist/frontend/lowering/scoped-type-memo.test.js.map +1 -0
  522. package/dist/frontend/lowering/static-typeof.d.ts +3 -1
  523. package/dist/frontend/lowering/static-typeof.js +6 -1
  524. package/dist/frontend/lowering/static-typeof.js.map +1 -1
  525. package/dist/frontend/lowering/strict-mode.d.ts +1 -5
  526. package/dist/frontend/lowering/strict-mode.js +4 -30
  527. package/dist/frontend/lowering/strict-mode.js.map +1 -1
  528. package/dist/frontend/lowering/structural-instances.d.ts +7 -0
  529. package/dist/frontend/lowering/structural-instances.js +23 -0
  530. package/dist/frontend/lowering/structural-instances.js.map +1 -1
  531. package/dist/frontend/lowering/surfaces.d.ts +15 -1
  532. package/dist/frontend/lowering/surfaces.js +78 -10
  533. package/dist/frontend/lowering/surfaces.js.map +1 -1
  534. package/dist/frontend/lowering/union-retag.d.ts +13 -1
  535. package/dist/frontend/lowering/union-retag.js +55 -1
  536. package/dist/frontend/lowering/union-retag.js.map +1 -1
  537. package/dist/frontend/lowering/union-retag.test.js +51 -0
  538. package/dist/frontend/lowering/union-retag.test.js.map +1 -1
  539. package/dist/frontend/lowering/unit-journal.d.ts +8 -0
  540. package/dist/frontend/lowering/unit-journal.js +14 -0
  541. package/dist/frontend/lowering/unit-journal.js.map +1 -1
  542. package/dist/frontend/lowering/unit-journal.test.js +36 -1
  543. package/dist/frontend/lowering/unit-journal.test.js.map +1 -1
  544. package/dist/frontend/lowering/zlib-constants.js +3 -2
  545. package/dist/frontend/lowering/zlib-constants.js.map +1 -1
  546. package/dist/frontend/npm-static.js +78 -9
  547. package/dist/frontend/npm-static.js.map +1 -1
  548. package/dist/frontend/npm-static.test.js +95 -2
  549. package/dist/frontend/npm-static.test.js.map +1 -1
  550. package/dist/frontend/pipeline.d.ts +5 -4
  551. package/dist/frontend/pipeline.js +94 -31
  552. package/dist/frontend/pipeline.js.map +1 -1
  553. package/dist/frontend/pipeline.test.js +68 -11
  554. package/dist/frontend/pipeline.test.js.map +1 -1
  555. package/dist/frontend/program.d.ts +62 -2
  556. package/dist/frontend/program.js +695 -422
  557. package/dist/frontend/program.js.map +1 -1
  558. package/dist/frontend/program.test.js +37 -1
  559. package/dist/frontend/program.test.js.map +1 -1
  560. package/dist/frontend/services-node.d.ts +7 -0
  561. package/dist/frontend/services-node.js +32 -1
  562. package/dist/frontend/services-node.js.map +1 -1
  563. package/dist/frontend/services-node.test.js +51 -0
  564. package/dist/frontend/services-node.test.js.map +1 -1
  565. package/dist/frontend/shape-inference/overlay.js +68 -2
  566. package/dist/frontend/shape-inference/overlay.js.map +1 -1
  567. package/dist/frontend/tier-analysis.d.ts +9 -0
  568. package/dist/frontend/tier-analysis.js +1 -0
  569. package/dist/frontend/tier-analysis.js.map +1 -1
  570. package/dist/frontend/tsc-codes.d.ts +57 -3
  571. package/dist/frontend/tsc-codes.js +935 -150
  572. package/dist/frontend/tsc-codes.js.map +1 -1
  573. package/dist/frontend/tsc-codes.test.js +221 -12
  574. package/dist/frontend/tsc-codes.test.js.map +1 -1
  575. package/dist/frontend/type-mapper.d.ts +91 -9
  576. package/dist/frontend/type-mapper.js +622 -181
  577. package/dist/frontend/type-mapper.js.map +1 -1
  578. package/dist/index.d.ts +1 -1
  579. package/dist/index.js +80 -15
  580. package/dist/index.js.map +1 -1
  581. package/dist/index.test.d.ts +1 -0
  582. package/dist/index.test.js +60 -0
  583. package/dist/index.test.js.map +1 -0
  584. package/dist/ir/builtin-effects.js +43 -0
  585. package/dist/ir/builtin-effects.js.map +1 -1
  586. package/dist/ir/builtin-signatures.d.ts +1 -1
  587. package/dist/ir/builtin-signatures.js +242 -16
  588. package/dist/ir/builtin-signatures.js.map +1 -1
  589. package/dist/ir/callback-specialization.d.ts +3 -2
  590. package/dist/ir/callback-specialization.js +35 -25
  591. package/dist/ir/callback-specialization.js.map +1 -1
  592. package/dist/ir/capture-values.d.ts +8 -4
  593. package/dist/ir/capture-values.js +9 -6
  594. package/dist/ir/capture-values.js.map +1 -1
  595. package/dist/ir/char-unit-locals.d.ts +6 -2
  596. package/dist/ir/char-unit-locals.js +11 -2
  597. package/dist/ir/char-unit-locals.js.map +1 -1
  598. package/dist/ir/class-key-index.d.ts +18 -0
  599. package/dist/ir/class-key-index.js +29 -0
  600. package/dist/ir/class-key-index.js.map +1 -0
  601. package/dist/ir/class-key-index.test.d.ts +1 -0
  602. package/dist/ir/class-key-index.test.js +25 -0
  603. package/dist/ir/class-key-index.test.js.map +1 -0
  604. package/dist/ir/codec.generated.d.ts +1 -1
  605. package/dist/ir/codec.generated.js +724 -648
  606. package/dist/ir/codec.generated.js.map +1 -1
  607. package/dist/ir/constant-globals.d.ts +5 -2
  608. package/dist/ir/constant-globals.js +25 -27
  609. package/dist/ir/constant-globals.js.map +1 -1
  610. package/dist/ir/expression-inlining.d.ts +4 -2
  611. package/dist/ir/expression-inlining.js +8 -2
  612. package/dist/ir/expression-inlining.js.map +1 -1
  613. package/dist/ir/field-values.d.ts +5 -2
  614. package/dist/ir/field-values.js +32 -21
  615. package/dist/ir/field-values.js.map +1 -1
  616. package/dist/ir/fields.generated.d.ts +11 -2
  617. package/dist/ir/fields.generated.js +8 -0
  618. package/dist/ir/fields.generated.js.map +1 -1
  619. package/dist/ir/final-fields.js +1 -1
  620. package/dist/ir/final-fields.js.map +1 -1
  621. package/dist/ir/function-references.d.ts +5 -4
  622. package/dist/ir/function-references.js +7 -4
  623. package/dist/ir/function-references.js.map +1 -1
  624. package/dist/ir/function-references.test.js +7 -0
  625. package/dist/ir/function-references.test.js.map +1 -1
  626. package/dist/ir/init-only-globals.d.ts +4 -2
  627. package/dist/ir/init-only-globals.js +17 -18
  628. package/dist/ir/init-only-globals.js.map +1 -1
  629. package/dist/ir/inline-array-views.js +1 -0
  630. package/dist/ir/inline-array-views.js.map +1 -1
  631. package/dist/ir/int32-slots.js +7 -0
  632. package/dist/ir/int32-slots.js.map +1 -1
  633. package/dist/ir/ir.d.ts +59 -4
  634. package/dist/ir/ir.js +7 -0
  635. package/dist/ir/ir.js.map +1 -1
  636. package/dist/ir/js-groups.d.ts +51 -0
  637. package/dist/ir/js-groups.js +394 -0
  638. package/dist/ir/js-groups.js.map +1 -0
  639. package/dist/ir/js-groups.test.d.ts +1 -0
  640. package/dist/ir/js-groups.test.js +555 -0
  641. package/dist/ir/js-groups.test.js.map +1 -0
  642. package/dist/ir/js-ic.js +30 -5
  643. package/dist/ir/js-ic.js.map +1 -1
  644. package/dist/ir/js-ic.test.js +27 -1
  645. package/dist/ir/js-ic.test.js.map +1 -1
  646. package/dist/ir/node-index.d.ts +23 -6
  647. package/dist/ir/node-index.js +126 -49
  648. package/dist/ir/node-index.js.map +1 -1
  649. package/dist/ir/numeric-call-specialization.d.ts +4 -2
  650. package/dist/ir/numeric-call-specialization.js +40 -26
  651. package/dist/ir/numeric-call-specialization.js.map +1 -1
  652. package/dist/ir/paired-while-loops.d.ts +4 -2
  653. package/dist/ir/paired-while-loops.js +8 -2
  654. package/dist/ir/paired-while-loops.js.map +1 -1
  655. package/dist/ir/parameter-versions.d.ts +13 -4
  656. package/dist/ir/parameter-versions.js +63 -42
  657. package/dist/ir/parameter-versions.js.map +1 -1
  658. package/dist/ir/property-bags.d.ts +4 -2
  659. package/dist/ir/property-bags.js +22 -17
  660. package/dist/ir/property-bags.js.map +1 -1
  661. package/dist/ir/row-pairs.d.ts +4 -2
  662. package/dist/ir/row-pairs.js +12 -11
  663. package/dist/ir/row-pairs.js.map +1 -1
  664. package/dist/ir/runtime-features.d.ts +87 -12
  665. package/dist/ir/runtime-features.js +263 -160
  666. package/dist/ir/runtime-features.js.map +1 -1
  667. package/dist/ir/runtime-features.test.js +109 -139
  668. package/dist/ir/runtime-features.test.js.map +1 -1
  669. package/dist/ir/runtime-jam-loops.d.ts +35 -0
  670. package/dist/ir/runtime-jam-loops.js +604 -0
  671. package/dist/ir/runtime-jam-loops.js.map +1 -0
  672. package/dist/ir/runtime-jam-loops.test.d.ts +1 -0
  673. package/dist/ir/runtime-jam-loops.test.js +565 -0
  674. package/dist/ir/runtime-jam-loops.test.js.map +1 -0
  675. package/dist/ir/saturating-loop-jams.d.ts +4 -2
  676. package/dist/ir/saturating-loop-jams.js +11 -10
  677. package/dist/ir/saturating-loop-jams.js.map +1 -1
  678. package/dist/ir/scalar-records.d.ts +5 -2
  679. package/dist/ir/scalar-records.js +12 -2
  680. package/dist/ir/scalar-records.js.map +1 -1
  681. package/dist/ir/self-captures.d.ts +4 -2
  682. package/dist/ir/self-captures.js +32 -27
  683. package/dist/ir/self-captures.js.map +1 -1
  684. package/dist/ir/serialize.d.ts +6 -1
  685. package/dist/ir/serialize.js +87 -23
  686. package/dist/ir/serialize.js.map +1 -1
  687. package/dist/ir/serialize.test.js +26 -0
  688. package/dist/ir/serialize.test.js.map +1 -1
  689. package/dist/ir/tiers.js +1 -0
  690. package/dist/ir/tiers.js.map +1 -1
  691. package/dist/ir/traverse.js +4 -0
  692. package/dist/ir/traverse.js.map +1 -1
  693. package/dist/ir/typed-argument-clones.d.ts +30 -0
  694. package/dist/ir/typed-argument-clones.js +789 -0
  695. package/dist/ir/typed-argument-clones.js.map +1 -0
  696. package/dist/ir/union-arm-loops.d.ts +3 -0
  697. package/dist/ir/union-arm-loops.js +373 -0
  698. package/dist/ir/union-arm-loops.js.map +1 -0
  699. package/dist/ir/union-arm-loops.test.d.ts +1 -0
  700. package/dist/ir/union-arm-loops.test.js +230 -0
  701. package/dist/ir/union-arm-loops.test.js.map +1 -0
  702. package/dist/ir/validate.js +88 -18
  703. package/dist/ir/validate.js.map +1 -1
  704. package/dist/library/compiler-self-identity.d.ts +8 -2
  705. package/dist/library/compiler-self-identity.js +92 -18
  706. package/dist/library/compiler-self-identity.js.map +1 -1
  707. package/dist/library/compiler-self-identity.test.js +150 -3
  708. package/dist/library/compiler-self-identity.test.js.map +1 -1
  709. package/dist/library/int-infer.d.ts +5 -0
  710. package/dist/library/int-infer.js +15 -3
  711. package/dist/library/int-infer.js.map +1 -1
  712. package/dist/library/ir-policy.js +1 -0
  713. package/dist/library/ir-policy.js.map +1 -1
  714. package/dist/library/library-cache.d.ts +4 -0
  715. package/dist/library/library-cache.js +2 -0
  716. package/dist/library/library-cache.js.map +1 -1
  717. package/dist/library/library-cache.test.js +26 -0
  718. package/dist/library/library-cache.test.js.map +1 -1
  719. package/dist/library/prepare.js +99 -31
  720. package/dist/library/prepare.js.map +1 -1
  721. package/dist/native/cache.d.ts +7 -0
  722. package/dist/native/cache.js +47 -0
  723. package/dist/native/cache.js.map +1 -1
  724. package/dist/native/cache.test.js +13 -1
  725. package/dist/native/cache.test.js.map +1 -1
  726. package/dist/native/cli.js +1 -1
  727. package/dist/native/cli.js.map +1 -1
  728. package/dist/native/compiler.js +18 -3
  729. package/dist/native/compiler.js.map +1 -1
  730. package/dist/native/executable-cache-open.test.js +31 -5
  731. package/dist/native/executable-cache-open.test.js.map +1 -1
  732. package/dist/native/executable-cache.d.ts +6 -1
  733. package/dist/native/executable-cache.js +7 -1
  734. package/dist/native/executable-cache.js.map +1 -1
  735. package/dist/native/prepare.d.ts +3 -0
  736. package/dist/native/prepare.js +43 -26
  737. package/dist/native/prepare.js.map +1 -1
  738. package/dist/native/prepare.test.js +25 -3
  739. package/dist/native/prepare.test.js.map +1 -1
  740. package/dist/native/sanitizer.js +10 -1
  741. package/dist/native/sanitizer.js.map +1 -1
  742. package/dist/native/sanitizer.test.js +7 -2
  743. package/dist/native/sanitizer.test.js.map +1 -1
  744. package/dist/node-islands/boundary.d.ts +12 -0
  745. package/dist/node-islands/boundary.js +38 -6
  746. package/dist/node-islands/boundary.js.map +1 -1
  747. package/dist/node-islands/boundary.test.d.ts +1 -0
  748. package/dist/node-islands/boundary.test.js +76 -0
  749. package/dist/node-islands/boundary.test.js.map +1 -0
  750. package/dist/node-islands/detect.d.ts +9 -0
  751. package/dist/node-islands/detect.js +110 -0
  752. package/dist/node-islands/detect.js.map +1 -1
  753. package/dist/node-islands/detect.test.js +24 -0
  754. package/dist/node-islands/detect.test.js.map +1 -1
  755. package/dist/node-islands/graph-islands.d.ts +40 -0
  756. package/dist/node-islands/graph-islands.js +128 -0
  757. package/dist/node-islands/graph-islands.js.map +1 -0
  758. package/dist/node-islands/growth.d.ts +57 -0
  759. package/dist/node-islands/growth.js +205 -0
  760. package/dist/node-islands/growth.js.map +1 -0
  761. package/dist/node-islands/report.d.ts +12 -0
  762. package/dist/node-islands/report.js +28 -0
  763. package/dist/node-islands/report.js.map +1 -1
  764. package/dist/node-islands/report.test.js +2 -0
  765. package/dist/node-islands/report.test.js.map +1 -1
  766. package/dist/node-islands/rules.js +5 -0
  767. package/dist/node-islands/rules.js.map +1 -1
  768. package/dist/node-islands/scan.d.ts +11 -2
  769. package/dist/node-islands/scan.js +61 -9
  770. package/dist/node-islands/scan.js.map +1 -1
  771. package/dist/wasm/translate.js +11 -5
  772. package/dist/wasm/translate.js.map +1 -1
  773. package/dist/wasm/translate.test.js +35 -0
  774. package/dist/wasm/translate.test.js.map +1 -1
  775. package/package.json +20 -20
  776. package/surface-manifest.json +184 -117
@@ -1,7 +1,8 @@
1
1
  import { primitiveConstructorOr } from "./lower-exprs.js";
2
2
  import { TO_STRING_TAG_FIELD, wellKnownSymbolOfField } from "./symbol-fields.js";
3
3
  import { InternalCompilerError } from "../../errors.js";
4
- import { dynUndefinedExpr, helperLoc, nodeThrowExpr, varRef } from "../../ir/build.js";
4
+ import { dynUndefinedExpr, helperLoc, nodeThrowExpr, numLit, varRef } from "../../ir/build.js";
5
+ import { classKeyHash } from "../../ir/class-key-index.js";
5
6
  import { constructedValue } from "./constructor-returns.js";
6
7
  import { eventTargetApiMembers, eventTargetInheritedMember } from "./lower-event-target.js";
7
8
  import { DATE_PROTOTYPE_METHOD_NAMES, DATE_TIME_FIELD, dateInheritedMember, dateRootOf, programDeclaresDateClass, } from "./builtins/date-classes.js";
@@ -15,6 +16,7 @@ import { erasedGenericInstance, implicitDefaultInstance } from "./generic-functi
15
16
  import {} from "./call-signatures.js";
16
17
  import { accessorCall, classValueRef, findGenericMethodOn, findGenericStaticOn, findMethodOn, findStaticOn, genericOverrideBelow, upcastTo, } from "./lower-classes.js";
17
18
  import { classPrototypeData, hasClassPrototypeData, prototypeReflectedFlag, observedPrototypeMethod, reflectClassPrototype, } from "./class-prototypes.js";
19
+ import { runtimeStaticDefines } from "./class-runtime-statics.js";
18
20
  import { perEvaluationPrivateNames } from "./private-brands.js";
19
21
  import { errorPropertyRead, errorPropertyWrite, errorToStringCall, errorToStringMethod, refreshErrorPropertyDispatch, refreshErrorMethodDispatch, } from "./error-methods.js";
20
22
  import { GeneratorDynamicDispatch } from "./generator-dynamic-dispatch.js";
@@ -360,6 +362,217 @@ function branchKind(cond, param) {
360
362
  return branchKind(cond.left, param);
361
363
  return null;
362
364
  }
365
+ /** The fewest distinct classes a run can dispatch on. Indexing costs a key
366
+ * load, a multiply and a compare tree whatever the table's size, while the
367
+ * chain costs a key test per class it skips: measured per read over tables
368
+ * read in rotation, indexing is 1.2 ns a read ahead at 20 classes, 4.1 ns at
369
+ * 40, 8.3 ns at 60 and 15 to 48 ns at 200. The crossover is far below this
370
+ * threshold, so what it decides is which tables change at all. Whole
371
+ * programs whose largest table holds fewer than this many classes measured
372
+ * within noise; the ones that gained (a nested decode -36.5%, 200-class reads
373
+ * -47%) gained through tables above it, and every smaller table keeps the
374
+ * chain it had. */
375
+ const MIN_CLASS_DISPATCH_CASES = 64;
376
+ /** A class table's branch whose condition tests one class's type key on a
377
+ * receiver local, or null for a statement of another form. A branch
378
+ * qualifies when it returns: a run is a dispatch, so the branch the switch
379
+ * selects leaves the helper rather than continuing into the statements after
380
+ * the run, which only the unselected branches would reach. */
381
+ function classBranch(stmt) {
382
+ if (stmt.kind !== "if" || stmt.else_ !== null)
383
+ return null;
384
+ const test = classKeyTest(stmt.cond);
385
+ if (test === null)
386
+ return null;
387
+ if (stmt.then[stmt.then.length - 1]?.kind !== "return")
388
+ return null;
389
+ if (assignsLocal(stmt.then, test.receiver))
390
+ return null;
391
+ if (leavesSwitch(stmt.then))
392
+ return null;
393
+ return test;
394
+ }
395
+ /** Whether the branch would `break` the switch its body moves into: an
396
+ * unlabeled break that no loop or switch inside the body binds. A labeled
397
+ * break and an unlabeled one already bound inside the body keep their
398
+ * targets. */
399
+ function leavesSwitch(statements) {
400
+ let found = false;
401
+ const scan = (body, bound) => {
402
+ for (const stmt of body) {
403
+ if (found)
404
+ return;
405
+ switch (stmt.kind) {
406
+ case "break":
407
+ if (stmt.label === undefined && bound === 0)
408
+ found = true;
409
+ break;
410
+ case "while":
411
+ case "doWhile":
412
+ case "for":
413
+ case "forOf":
414
+ scan(stmt.body, bound + 1);
415
+ break;
416
+ case "switch":
417
+ for (const { body: caseBody } of stmt.cases)
418
+ scan(caseBody, bound + 1);
419
+ break;
420
+ case "if":
421
+ scan(stmt.then, bound);
422
+ if (stmt.else_)
423
+ scan(stmt.else_, bound);
424
+ break;
425
+ case "block":
426
+ scan(stmt.body, bound);
427
+ break;
428
+ case "tryCatch":
429
+ scan(stmt.tryBody, bound);
430
+ if (stmt.catchBody)
431
+ scan(stmt.catchBody, bound);
432
+ if (stmt.finallyBody)
433
+ scan(stmt.finallyBody, bound);
434
+ break;
435
+ default:
436
+ break;
437
+ }
438
+ }
439
+ };
440
+ scan(statements, 0);
441
+ return found;
442
+ }
443
+ /** The receiver local and interned type key of `dyn.typedRefIs(v, "object:C")`,
444
+ * or of the branch-conditional form `test ? instanceOf(v, C) : false`. The
445
+ * key must be ASCII: the dispatch indexes on the key's length and last four
446
+ * bytes, which for ASCII are the key text's own. */
447
+ function classKeyTest(cond) {
448
+ if (cond.kind === "ternary" && cond.else_.kind === "boolLit" && cond.else_.value === false)
449
+ return classKeyTest(cond.cond);
450
+ if (cond.kind !== "libCall" || cond.fn !== "dyn.typedRefIs" || cond.args.length !== 2)
451
+ return null;
452
+ const [value, key] = cond.args;
453
+ if (value?.kind !== "varRef" || key?.kind !== "strLit")
454
+ return null;
455
+ if (!key.value.startsWith("object:") || !/^[\x20-\x7e]*$/.test(key.value))
456
+ return null;
457
+ return { value, receiver: value.localId, key: key.value };
458
+ }
459
+ /** Whether the branch writes its receiver local, which would make the
460
+ * dispatch read a value the branch tests do not. */
461
+ function assignsLocal(statements, localId) {
462
+ let found = false;
463
+ everyStmtList(statements, {
464
+ stmt: (stmt) => {
465
+ if ((stmt.kind === "assign" || stmt.kind === "varDecl" || stmt.kind === "forOf") &&
466
+ stmt.localId === localId)
467
+ found = true;
468
+ return !found;
469
+ },
470
+ expr: () => !found,
471
+ });
472
+ return found;
473
+ }
474
+ /** The class branches of a generated table, whether its body lists them or
475
+ * reaches them through the indexed dispatch indexBranchRuns builds. The
476
+ * passes that read a table's branches run after it: the switch selects a
477
+ * branch by its class's key and the branch keeps its own key guard, so a
478
+ * reader treats the branches as the chain they were lowered from. */
479
+ function classTableBranches(body) {
480
+ if (!body.some(isClassDispatch))
481
+ return body;
482
+ const branches = [];
483
+ for (const stmt of body) {
484
+ if (isClassDispatch(stmt))
485
+ for (const { body: caseBody } of stmt.cases)
486
+ branches.push(...caseBody);
487
+ else
488
+ branches.push(stmt);
489
+ }
490
+ return branches;
491
+ }
492
+ /** The switch indexBranchRuns builds over a table's branches. */
493
+ function isClassDispatch(stmt) {
494
+ return stmt.kind === "switch" && stmt.disc.kind === "libCall" && stmt.disc.fn === "dyn.classHash";
495
+ }
496
+ /** The run's leading branches that stay in the chain ahead of the switch.
497
+ * Indexing costs a key load, a multiply and a walk of the compare tree before
498
+ * the matching branch's own guard runs, so a class the table tests early is
499
+ * cheaper in the chain: a read that hits one of them never computes the
500
+ * index. Keeping the first two measured the difference: one effect program
501
+ * whose tables are large but read near their front ran 3.3% slower with every
502
+ * branch in the switch (757.0 ms against 735.5 ms over 30 interleaved rounds)
503
+ * and at the baseline time with two peeled (737.5 ms), while a 200-class read,
504
+ * where the hit sits deep, keeps its gain. */
505
+ const CLASS_DISPATCH_HEAD = 2;
506
+ /** Replace each run of consecutive class branches on one receiver (at least
507
+ * MIN_CLASS_DISPATCH_CASES distinct classes) with a switch that selects the
508
+ * receiver's class. The branches move into the switch's cases unchanged and
509
+ * in order, branches whose keys hash together in one case; a key shared
510
+ * with a class outside the table selects that case, whose guards are false,
511
+ * and the switch's fallthrough reaches the remaining guards and the
512
+ * statements after the run exactly as the chain would. The run's first
513
+ * CLASS_DISPATCH_HEAD branches stay in the chain ahead of the switch: they
514
+ * run in order before it, and a class they select returns as it always did,
515
+ * so the switch only sees the receiver once those tests have failed. */
516
+ function indexBranchRuns(body) {
517
+ let rebuilt = null;
518
+ let i = 0;
519
+ while (i < body.length) {
520
+ const start = i;
521
+ const first = classBranch(body[i]);
522
+ if (first === null) {
523
+ rebuilt?.push(body[i]);
524
+ i++;
525
+ continue;
526
+ }
527
+ const run = [];
528
+ let branch = first;
529
+ while (branch !== null && branch.receiver === first.receiver) {
530
+ run.push({ value: branch.value, receiver: branch.receiver, key: branch.key, stmt: body[i] });
531
+ i++;
532
+ branch = i < body.length ? classBranch(body[i]) : null;
533
+ }
534
+ const keys = [...new Set(run.map((branch) => branch.key))];
535
+ if (keys.length < MIN_CLASS_DISPATCH_CASES) {
536
+ if (rebuilt)
537
+ for (const branch of run)
538
+ rebuilt.push(branch.stmt);
539
+ continue;
540
+ }
541
+ rebuilt ??= body.slice(0, start);
542
+ const head = Math.min(CLASS_DISPATCH_HEAD, run.length - 1);
543
+ for (const branch of run.slice(0, head))
544
+ rebuilt.push(branch.stmt);
545
+ rebuilt.push(classDispatch(run.slice(head)));
546
+ }
547
+ return rebuilt ?? body;
548
+ }
549
+ /** The switch that selects one of the run's branches, keyed by the class
550
+ * hash the emitted code computes from the receiver's key. */
551
+ function classDispatch(run) {
552
+ const first = run[0];
553
+ const loc = first.stmt.loc;
554
+ const branches = new Map();
555
+ for (const branch of run) {
556
+ const hash = classKeyHash(branch.key);
557
+ const ofHash = branches.get(hash);
558
+ if (ofHash)
559
+ ofHash.push(branch.stmt);
560
+ else
561
+ branches.set(hash, [branch.stmt]);
562
+ }
563
+ return {
564
+ kind: "switch",
565
+ disc: {
566
+ kind: "libCall",
567
+ fn: "dyn.classHash",
568
+ args: [varRef(first.receiver, first.value.type, loc)],
569
+ type: F64,
570
+ loc,
571
+ },
572
+ cases: [...branches].map(([hash, body]) => ({ test: numLit(hash, loc), body })),
573
+ loc,
574
+ };
575
+ }
363
576
  const READ_PROPERTIES = "%dyn.class.readProperties";
364
577
  const READ_PROPERTIES_OR_EMPTY = "%dyn.class.readPropertiesOrEmpty";
365
578
  function isEmptyBag(value) {
@@ -629,7 +842,7 @@ export function boxClassInstancesExactly(lowerer, functions) {
629
842
  return;
630
843
  // Static class → its constructible descendants in normalization order.
631
844
  const branches = new Map();
632
- for (const stmt of normalize.body) {
845
+ for (const stmt of classTableBranches(normalize.body)) {
633
846
  if (stmt.kind !== "if" || stmt.cond.kind !== "libCall" || stmt.cond.fn !== "dyn.typedRefIs")
634
847
  continue;
635
848
  const key = stmt.cond.args[1];
@@ -1838,23 +2051,33 @@ export class ClassDynamicDispatch {
1838
2051
  // every reachability pass. Recompute this set as new bodies appear.
1839
2052
  if (this.generated.has(fn) || !rewrite.has(fn))
1840
2053
  continue;
1841
- const keyInitializers = new Map();
1842
- const written = new Set();
1843
- everyStmtList(fn.body, {
1844
- expr: (expression) => {
1845
- if (expression.kind === "incDec" || expression.kind === "assignExpr")
1846
- written.add(expression.localId);
1847
- return true;
1848
- },
1849
- stmt: (statement) => {
1850
- if (statement.kind === "varDecl" && statement.init)
1851
- keyInitializers.set(statement.localId, statement.init);
1852
- if (statement.kind === "assign")
1853
- written.add(statement.localId);
1854
- return true;
1855
- },
1856
- });
2054
+ // The bindings a key expression reads through, and the ones a write
2055
+ // rebinds. Only a dynamic-key site asks for them, so a body without one
2056
+ // keeps its IR walk.
2057
+ let keyTables = null;
2058
+ const keysOf = () => {
2059
+ if (keyTables !== null)
2060
+ return keyTables;
2061
+ const initializers = new Map();
2062
+ const written = new Set();
2063
+ everyStmtList(fn.body, {
2064
+ expr: (expression) => {
2065
+ if (expression.kind === "incDec" || expression.kind === "assignExpr")
2066
+ written.add(expression.localId);
2067
+ return true;
2068
+ },
2069
+ stmt: (statement) => {
2070
+ if (statement.kind === "varDecl" && statement.init)
2071
+ initializers.set(statement.localId, statement.init);
2072
+ if (statement.kind === "assign")
2073
+ written.add(statement.localId);
2074
+ return true;
2075
+ },
2076
+ });
2077
+ return (keyTables = { initializers, written });
2078
+ };
1857
2079
  const keyValue = (value) => {
2080
+ const { initializers: keyInitializers, written } = keysOf();
1858
2081
  const visited = new Set();
1859
2082
  while (true) {
1860
2083
  if (value.kind === "dynFrom") {
@@ -1876,1056 +2099,885 @@ export class ClassDynamicDispatch {
1876
2099
  return value;
1877
2100
  }
1878
2101
  };
1879
- fn.body = transformStmtList(fn.body, {
1880
- stmt: (stmt) => stmt,
1881
- expr: (expr) => {
1882
- if (expr.kind === "dynHasKey" && prototypeMembers.has(expr.key)) {
1883
- // A class instance's snapshot can carry its class's prototype
1884
- // data, which holds only the methods the program reads through
1885
- // the prototype. The computed-key form answers methods and
1886
- // accessors from the class itself.
2102
+ const rewriteExpr = (expr) => {
2103
+ if (expr.kind === "dynHasKey" && prototypeMembers.has(expr.key)) {
2104
+ // A class instance's snapshot can carry its class's prototype
2105
+ // data, which holds only the methods the program reads through
2106
+ // the prototype. The computed-key form answers methods and
2107
+ // accessors from the class itself.
2108
+ const loc = expr.loc;
2109
+ const test = {
2110
+ kind: "libCall",
2111
+ fn: "dyn.hasKeyComputed",
2112
+ args: [
2113
+ expr.value,
2114
+ {
2115
+ kind: "dynFrom",
2116
+ value: { kind: "strLit", value: expr.key, type: STRING, loc },
2117
+ type: DYN,
2118
+ loc,
2119
+ },
2120
+ ],
2121
+ type: BOOL,
2122
+ loc,
2123
+ };
2124
+ changed = true;
2125
+ return {
2126
+ kind: "seqExpr",
2127
+ stmts: [],
2128
+ result: expr.negated
2129
+ ? { kind: "unary", op: "!", operand: test, type: BOOL, loc }
2130
+ : test,
2131
+ type: BOOL,
2132
+ loc,
2133
+ };
2134
+ }
2135
+ const called = calling.size ? this.convertMethodCall(lowerer, fn, expr, calling) : null;
2136
+ if (called) {
2137
+ changed = true;
2138
+ return called;
2139
+ }
2140
+ const converted = converting.size
2141
+ ? this.convertOperands(lowerer, fn, expr, converting)
2142
+ : null;
2143
+ if (converted) {
2144
+ changed = true;
2145
+ // A hoisting sequence revisits the operation as its child; a
2146
+ // wrapped operation continues through the rewrites below.
2147
+ if (converted.kind === "seqExpr")
2148
+ return converted;
2149
+ expr = converted;
2150
+ }
2151
+ if (expr.kind === "dynCheck" && isDynTypedRefType(expr.type)) {
2152
+ const type = expr.type;
2153
+ let cast = this.checkedCasts.get(type.className);
2154
+ if (!cast) {
1887
2155
  const loc = expr.loc;
1888
- const test = {
1889
- kind: "libCall",
1890
- fn: "dyn.hasKeyComputed",
1891
- args: [
1892
- expr.value,
1893
- {
1894
- kind: "dynFrom",
1895
- value: { kind: "strLit", value: expr.key, type: STRING, loc },
1896
- type: DYN,
1897
- loc,
1898
- },
1899
- ],
1900
- type: BOOL,
2156
+ const fn = {
2157
+ name: `%dyn.class.cast:${type.className}`,
2158
+ params: [{ localId: "value", name: "value", type: DYN }],
2159
+ locals: [{ id: "value", name: "value", type: DYN, mutable: false }],
2160
+ returnType: type,
2161
+ body: [{ kind: "return", value: { ...expr, value: varRef("value", DYN, loc) }, loc }],
1901
2162
  loc,
1902
2163
  };
2164
+ cast = { fn, classes: new Set() };
2165
+ this.checkedCasts.set(type.className, cast);
2166
+ this.generated.add(fn);
2167
+ lowerer.liftedFns.push(fn);
1903
2168
  changed = true;
1904
- return {
1905
- kind: "seqExpr",
1906
- stmts: [],
1907
- result: expr.negated
1908
- ? { kind: "unary", op: "!", operand: test, type: BOOL, loc }
1909
- : test,
1910
- type: BOOL,
2169
+ }
2170
+ return { kind: "call", callee: cast.fn.name, args: [expr.value], type, loc: expr.loc };
2171
+ }
2172
+ if (expr.kind === "libCall" && expr.fn === "dyn.inheritsErrorPrototype") {
2173
+ if (!this.errorPrototypeHelper) {
2174
+ const loc = expr.loc;
2175
+ this.errorPrototypeHelper = {
2176
+ name: "%dyn.class.inheritsErrorPrototype",
2177
+ params: [{ localId: "value", name: "value", type: DYN }],
2178
+ locals: [{ id: "value", name: "value", type: DYN, mutable: false }],
2179
+ returnType: BOOL,
1911
2180
  loc,
2181
+ body: [
2182
+ { kind: "return", value: { ...expr, args: [varRef("value", DYN, loc)] }, loc },
2183
+ ],
1912
2184
  };
1913
- }
1914
- const called = calling.size ? this.convertMethodCall(lowerer, fn, expr, calling) : null;
1915
- if (called) {
1916
- changed = true;
1917
- return called;
1918
- }
1919
- const converted = converting.size
1920
- ? this.convertOperands(lowerer, fn, expr, converting)
1921
- : null;
1922
- if (converted) {
2185
+ lowerer.liftedFns.push(this.errorPrototypeHelper);
2186
+ this.generated.add(this.errorPrototypeHelper);
1923
2187
  changed = true;
1924
- // A hoisting sequence revisits the operation as its child; a
1925
- // wrapped operation continues through the rewrites below.
1926
- if (converted.kind === "seqExpr")
1927
- return converted;
1928
- expr = converted;
1929
- }
1930
- if (expr.kind === "dynCheck" && isDynTypedRefType(expr.type)) {
1931
- const type = expr.type;
1932
- let cast = this.checkedCasts.get(type.className);
1933
- if (!cast) {
1934
- const loc = expr.loc;
1935
- const fn = {
1936
- name: `%dyn.class.cast:${type.className}`,
1937
- params: [{ localId: "value", name: "value", type: DYN }],
1938
- locals: [{ id: "value", name: "value", type: DYN, mutable: false }],
1939
- returnType: type,
1940
- body: [
1941
- { kind: "return", value: { ...expr, value: varRef("value", DYN, loc) }, loc },
1942
- ],
1943
- loc,
1944
- };
1945
- cast = { fn, classes: new Set() };
1946
- this.checkedCasts.set(type.className, cast);
1947
- this.generated.add(fn);
1948
- lowerer.liftedFns.push(fn);
1949
- changed = true;
1950
- }
1951
- return { kind: "call", callee: cast.fn.name, args: [expr.value], type, loc: expr.loc };
1952
2188
  }
1953
- if (expr.kind === "libCall" && expr.fn === "dyn.inheritsErrorPrototype") {
1954
- if (!this.errorPrototypeHelper) {
2189
+ return {
2190
+ kind: "call",
2191
+ callee: this.errorPrototypeHelper.name,
2192
+ args: expr.args,
2193
+ type: BOOL,
2194
+ loc: expr.loc,
2195
+ };
2196
+ }
2197
+ if (expr.kind === "libCall" &&
2198
+ (expr.fn === "dyn.getPrototype" || expr.fn === "dyn.getPrototypeForIdentity") &&
2199
+ expr.args[0]?.kind !== "dynObjLit") {
2200
+ if (expr.prototypeIdentityOnly) {
2201
+ let helper = this.prototypeIdentityHelpers.get(expr.fn);
2202
+ if (!helper) {
1955
2203
  const loc = expr.loc;
1956
- this.errorPrototypeHelper = {
1957
- name: "%dyn.class.inheritsErrorPrototype",
1958
- params: [{ localId: "value", name: "value", type: DYN }],
1959
- locals: [{ id: "value", name: "value", type: DYN, mutable: false }],
1960
- returnType: BOOL,
1961
- loc,
1962
- body: [
1963
- { kind: "return", value: { ...expr, args: [varRef("value", DYN, loc)] }, loc },
1964
- ],
2204
+ helper = {
2205
+ fn: {
2206
+ name: expr.fn === "dyn.getPrototype"
2207
+ ? "%dyn.class.prototypeIdentity"
2208
+ : "%dyn.class.prototypeChainIdentity",
2209
+ params: [{ localId: "value", name: "value", type: DYN }],
2210
+ locals: [{ id: "value", name: "value", type: DYN, mutable: false }],
2211
+ returnType: DYN,
2212
+ loc,
2213
+ body: [
2214
+ {
2215
+ kind: "return",
2216
+ value: { ...expr, args: [varRef("value", DYN, loc)] },
2217
+ loc,
2218
+ },
2219
+ ],
2220
+ },
2221
+ classes: new Set(),
1965
2222
  };
1966
- lowerer.liftedFns.push(this.errorPrototypeHelper);
1967
- this.generated.add(this.errorPrototypeHelper);
2223
+ this.prototypeIdentityHelpers.set(expr.fn, helper);
2224
+ lowerer.liftedFns.push(helper.fn);
2225
+ this.generated.add(helper.fn);
1968
2226
  changed = true;
1969
2227
  }
1970
2228
  return {
1971
2229
  kind: "call",
1972
- callee: this.errorPrototypeHelper.name,
2230
+ callee: helper.fn.name,
1973
2231
  args: expr.args,
1974
- type: BOOL,
2232
+ type: DYN,
1975
2233
  loc: expr.loc,
1976
2234
  };
1977
2235
  }
1978
- if (expr.kind === "libCall" &&
1979
- (expr.fn === "dyn.getPrototype" || expr.fn === "dyn.getPrototypeForIdentity") &&
1980
- expr.args[0]?.kind !== "dynObjLit") {
1981
- if (expr.prototypeIdentityOnly) {
1982
- let helper = this.prototypeIdentityHelpers.get(expr.fn);
1983
- if (!helper) {
1984
- const loc = expr.loc;
1985
- helper = {
1986
- fn: {
1987
- name: expr.fn === "dyn.getPrototype"
1988
- ? "%dyn.class.prototypeIdentity"
1989
- : "%dyn.class.prototypeChainIdentity",
1990
- params: [{ localId: "value", name: "value", type: DYN }],
1991
- locals: [{ id: "value", name: "value", type: DYN, mutable: false }],
1992
- returnType: DYN,
1993
- loc,
1994
- body: [
1995
- {
1996
- kind: "return",
1997
- value: { ...expr, args: [varRef("value", DYN, loc)] },
1998
- loc,
1999
- },
2000
- ],
2001
- },
2002
- classes: new Set(),
2003
- };
2004
- this.prototypeIdentityHelpers.set(expr.fn, helper);
2005
- lowerer.liftedFns.push(helper.fn);
2006
- this.generated.add(helper.fn);
2007
- changed = true;
2008
- }
2009
- return {
2010
- kind: "call",
2011
- callee: helper.fn.name,
2012
- args: expr.args,
2013
- type: DYN,
2014
- loc: expr.loc,
2015
- };
2016
- }
2017
- if (!this.prototypeHelper) {
2018
- const loc = expr.loc;
2019
- this.prototypeHelper = {
2020
- name: "%dyn.class.getPrototype",
2021
- params: [{ localId: "value", name: "value", type: DYN }],
2022
- locals: [{ id: "value", name: "value", type: DYN, mutable: false }],
2023
- returnType: DYN,
2024
- loc,
2025
- body: [
2026
- { kind: "return", value: { ...expr, args: [varRef("value", DYN, loc)] }, loc },
2027
- ],
2028
- };
2029
- lowerer.liftedFns.push(this.prototypeHelper);
2030
- this.generated.add(this.prototypeHelper);
2031
- changed = true;
2032
- }
2033
- return {
2034
- kind: "call",
2035
- callee: this.prototypeHelper.name,
2036
- args: expr.args,
2037
- type: DYN,
2038
- loc: expr.loc,
2236
+ if (!this.prototypeHelper) {
2237
+ const loc = expr.loc;
2238
+ this.prototypeHelper = {
2239
+ name: "%dyn.class.getPrototype",
2240
+ params: [{ localId: "value", name: "value", type: DYN }],
2241
+ locals: [{ id: "value", name: "value", type: DYN, mutable: false }],
2242
+ returnType: DYN,
2243
+ loc,
2244
+ body: [
2245
+ { kind: "return", value: { ...expr, args: [varRef("value", DYN, loc)] }, loc },
2246
+ ],
2039
2247
  };
2248
+ lowerer.liftedFns.push(this.prototypeHelper);
2249
+ this.generated.add(this.prototypeHelper);
2250
+ changed = true;
2040
2251
  }
2041
- if (expr.kind === "libCall" &&
2042
- (expr.fn === "dyn.toString" || expr.fn === "dyn.stringConstructor") &&
2043
- lowerer.classes.has("%Error")) {
2044
- const key = JSON.stringify([expr.fn, ...expr.args.map((arg) => typeKey(arg.type))]);
2045
- let errorString = this.errorStrings.get(key);
2046
- if (!errorString) {
2047
- const loc = expr.loc;
2048
- const params = expr.args.map((arg, i) => ({
2049
- localId: `p.${i}`,
2050
- name: `p${i}`,
2051
- type: arg.type,
2052
- }));
2053
- const value = varRef("p.0", DYN, loc);
2054
- errorString = {
2055
- name: `%dyn.error.${expr.fn.slice(4)}.${this.errorStrings.size}`,
2056
- params,
2057
- returnType: STRING,
2058
- locals: params.map((p) => ({
2059
- id: p.localId,
2060
- name: p.name,
2061
- type: p.type,
2062
- mutable: false,
2063
- })),
2064
- loc,
2065
- body: [
2066
- {
2067
- kind: "if",
2068
- cond: { kind: "dynTest", test: "error", value, type: BOOL, loc },
2069
- then: [
2070
- {
2071
- kind: "return",
2252
+ return {
2253
+ kind: "call",
2254
+ callee: this.prototypeHelper.name,
2255
+ args: expr.args,
2256
+ type: DYN,
2257
+ loc: expr.loc,
2258
+ };
2259
+ }
2260
+ if (expr.kind === "libCall" &&
2261
+ (expr.fn === "dyn.toString" || expr.fn === "dyn.stringConstructor") &&
2262
+ lowerer.classes.has("%Error")) {
2263
+ const key = JSON.stringify([expr.fn, ...expr.args.map((arg) => typeKey(arg.type))]);
2264
+ let errorString = this.errorStrings.get(key);
2265
+ if (!errorString) {
2266
+ const loc = expr.loc;
2267
+ const params = expr.args.map((arg, i) => ({
2268
+ localId: `p.${i}`,
2269
+ name: `p${i}`,
2270
+ type: arg.type,
2271
+ }));
2272
+ const value = varRef("p.0", DYN, loc);
2273
+ errorString = {
2274
+ name: `%dyn.error.${expr.fn.slice(4)}.${this.errorStrings.size}`,
2275
+ params,
2276
+ returnType: STRING,
2277
+ locals: params.map((p) => ({
2278
+ id: p.localId,
2279
+ name: p.name,
2280
+ type: p.type,
2281
+ mutable: false,
2282
+ })),
2283
+ loc,
2284
+ body: [
2285
+ {
2286
+ kind: "if",
2287
+ cond: { kind: "dynTest", test: "error", value, type: BOOL, loc },
2288
+ then: [
2289
+ {
2290
+ kind: "return",
2291
+ value: {
2292
+ kind: "dynCheck",
2293
+ type: STRING,
2294
+ loc,
2072
2295
  value: {
2073
- kind: "dynCheck",
2074
- type: STRING,
2075
- loc,
2076
- value: {
2077
- kind: "dynCall",
2078
- callee: errorToStringMethod(lowerer, {
2079
- kind: "dynCheck",
2080
- value,
2081
- type: { kind: "object", className: "%Error" },
2082
- loc,
2083
- }),
2084
- receiver: value,
2085
- calleeName: "value.toString",
2086
- args: params
2087
- .slice(1)
2088
- .map((p) => lowerer.coerceToExpected(varRef(p.localId, p.type, loc), DYN)),
2089
- type: DYN,
2296
+ kind: "dynCall",
2297
+ callee: errorToStringMethod(lowerer, {
2298
+ kind: "dynCheck",
2299
+ value,
2300
+ type: { kind: "object", className: "%Error" },
2090
2301
  loc,
2091
- },
2302
+ }),
2303
+ receiver: value,
2304
+ calleeName: "value.toString",
2305
+ args: params
2306
+ .slice(1)
2307
+ .map((p) => lowerer.coerceToExpected(varRef(p.localId, p.type, loc), DYN)),
2308
+ type: DYN,
2309
+ loc,
2092
2310
  },
2093
- loc,
2094
2311
  },
2095
- ],
2096
- else_: null,
2097
- loc,
2098
- },
2099
- {
2100
- kind: "return",
2101
- value: { ...expr, args: params.map((p) => varRef(p.localId, p.type, loc)) },
2102
- loc,
2103
- },
2104
- ],
2105
- };
2106
- this.errorStrings.set(key, errorString);
2107
- this.generated.add(errorString);
2108
- lowerer.liftedFns.push(errorString);
2109
- changed = true;
2110
- }
2111
- return {
2112
- kind: "call",
2113
- callee: errorString.name,
2114
- args: expr.args,
2115
- type: STRING,
2116
- loc: expr.loc,
2312
+ loc,
2313
+ },
2314
+ ],
2315
+ else_: null,
2316
+ loc,
2317
+ },
2318
+ {
2319
+ kind: "return",
2320
+ value: { ...expr, args: params.map((p) => varRef(p.localId, p.type, loc)) },
2321
+ loc,
2322
+ },
2323
+ ],
2117
2324
  };
2325
+ this.errorStrings.set(key, errorString);
2326
+ this.generated.add(errorString);
2327
+ lowerer.liftedFns.push(errorString);
2328
+ changed = true;
2118
2329
  }
2119
- if (expr.kind === "call" &&
2120
- (expr.callee === this.propertyBag.name || expr.callee === "%dyn.class.readProperties")) {
2121
- const boxed = expr.args[0];
2122
- if (boxed?.kind === "dynFrom" && isDynTypedRefType(boxed.value.type)) {
2123
- const helper = this.typedPropertyBag(lowerer, boxed.value.type, expr.loc, expr.callee === "%dyn.class.readProperties");
2124
- if (helper) {
2125
- changed = true;
2126
- return { ...expr, callee: helper.name, args: [boxed.value] };
2127
- }
2330
+ return {
2331
+ kind: "call",
2332
+ callee: errorString.name,
2333
+ args: expr.args,
2334
+ type: STRING,
2335
+ loc: expr.loc,
2336
+ };
2337
+ }
2338
+ if (expr.kind === "call" &&
2339
+ (expr.callee === this.propertyBag.name || expr.callee === "%dyn.class.readProperties")) {
2340
+ const boxed = expr.args[0];
2341
+ if (boxed?.kind === "dynFrom" && isDynTypedRefType(boxed.value.type)) {
2342
+ const helper = this.typedPropertyBag(lowerer, boxed.value.type, expr.loc, expr.callee === "%dyn.class.readProperties");
2343
+ if (helper) {
2344
+ changed = true;
2345
+ return { ...expr, callee: helper.name, args: [boxed.value] };
2128
2346
  }
2129
2347
  }
2130
- if (expr.kind === "libCall" && expr.fn === "bytes.construct") {
2131
- if (!this.constructDispatch) {
2132
- const loc = expr.loc;
2133
- const params = [DYN, DYN, STRING].map((type, i) => ({
2134
- localId: `p.${i}`,
2135
- name: `p${i}`,
2136
- type,
2137
- }));
2138
- this.constructDispatch = {
2139
- name: "%dyn.class.construct",
2140
- params,
2141
- returnType: DYN,
2142
- locals: params.map((p) => ({
2143
- id: p.localId,
2144
- name: p.name,
2145
- type: p.type,
2146
- mutable: false,
2147
- })),
2148
- body: [
2149
- {
2150
- kind: "return",
2151
- value: { ...expr, args: params.map((p) => varRef(p.localId, p.type, loc)) },
2152
- loc,
2153
- },
2154
- ],
2155
- loc,
2156
- };
2157
- this.generated.add(this.constructDispatch);
2158
- lowerer.liftedFns.push(this.constructDispatch);
2159
- changed = true;
2160
- }
2161
- return {
2162
- kind: "call",
2163
- callee: this.constructDispatch.name,
2164
- args: expr.args,
2165
- type: DYN,
2166
- loc: expr.loc,
2348
+ }
2349
+ if (expr.kind === "libCall" && expr.fn === "bytes.construct") {
2350
+ if (!this.constructDispatch) {
2351
+ const loc = expr.loc;
2352
+ const params = [DYN, DYN, STRING].map((type, i) => ({
2353
+ localId: `p.${i}`,
2354
+ name: `p${i}`,
2355
+ type,
2356
+ }));
2357
+ this.constructDispatch = {
2358
+ name: "%dyn.class.construct",
2359
+ params,
2360
+ returnType: DYN,
2361
+ locals: params.map((p) => ({
2362
+ id: p.localId,
2363
+ name: p.name,
2364
+ type: p.type,
2365
+ mutable: false,
2366
+ })),
2367
+ body: [
2368
+ {
2369
+ kind: "return",
2370
+ value: { ...expr, args: params.map((p) => varRef(p.localId, p.type, loc)) },
2371
+ loc,
2372
+ },
2373
+ ],
2374
+ loc,
2167
2375
  };
2376
+ this.generated.add(this.constructDispatch);
2377
+ lowerer.liftedFns.push(this.constructDispatch);
2378
+ changed = true;
2168
2379
  }
2169
- if (expr.kind === "libCall" &&
2170
- (expr.fn === "dyn.forInKeys" || expr.fn === "dyn.forInKeyStrings")) {
2171
- let enumeration = this.enumerations.get(expr.fn);
2172
- if (!enumeration) {
2173
- const loc = expr.loc;
2174
- const value = varRef("p.0", DYN, loc);
2175
- enumeration = {
2176
- name: expr.fn === "dyn.forInKeys"
2177
- ? "%dyn.class.forInKeys"
2178
- : "%dyn.class.forInKeyStrings",
2179
- params: [{ localId: "p.0", name: "value", type: DYN }],
2180
- returnType: expr.type,
2181
- locals: [{ id: "p.0", name: "value", type: DYN, mutable: false }],
2182
- body: [{ kind: "return", value: { ...expr, args: [value] }, loc }],
2183
- loc,
2184
- };
2185
- this.enumerations.set(expr.fn, enumeration);
2186
- this.generated.add(enumeration);
2187
- lowerer.liftedFns.push(enumeration);
2188
- changed = true;
2189
- }
2190
- return {
2191
- kind: "call",
2192
- callee: enumeration.name,
2193
- args: expr.args,
2194
- type: expr.type,
2195
- loc: expr.loc,
2380
+ return {
2381
+ kind: "call",
2382
+ callee: this.constructDispatch.name,
2383
+ args: expr.args,
2384
+ type: DYN,
2385
+ loc: expr.loc,
2386
+ };
2387
+ }
2388
+ if (expr.kind === "libCall" &&
2389
+ (expr.fn === "dyn.forInKeys" || expr.fn === "dyn.forInKeyStrings")) {
2390
+ let enumeration = this.enumerations.get(expr.fn);
2391
+ if (!enumeration) {
2392
+ const loc = expr.loc;
2393
+ const value = varRef("p.0", DYN, loc);
2394
+ enumeration = {
2395
+ name: expr.fn === "dyn.forInKeys" ? "%dyn.class.forInKeys" : "%dyn.class.forInKeyStrings",
2396
+ params: [{ localId: "p.0", name: "value", type: DYN }],
2397
+ returnType: expr.type,
2398
+ locals: [{ id: "p.0", name: "value", type: DYN, mutable: false }],
2399
+ body: [{ kind: "return", value: { ...expr, args: [value] }, loc }],
2400
+ loc,
2196
2401
  };
2402
+ this.enumerations.set(expr.fn, enumeration);
2403
+ this.generated.add(enumeration);
2404
+ lowerer.liftedFns.push(enumeration);
2405
+ changed = true;
2197
2406
  }
2198
- if (expr.kind === "libCall" && expr.fn === "dyn.defineProperty") {
2199
- const loc = expr.loc;
2200
- if (!this.descriptorHelper) {
2201
- const params = ["target", "key", "descriptor"].map((name) => ({
2202
- localId: name,
2203
- name,
2407
+ return {
2408
+ kind: "call",
2409
+ callee: enumeration.name,
2410
+ args: expr.args,
2411
+ type: expr.type,
2412
+ loc: expr.loc,
2413
+ };
2414
+ }
2415
+ if (expr.kind === "libCall" && expr.fn === "dyn.defineProperty") {
2416
+ const loc = expr.loc;
2417
+ if (!this.descriptorHelper) {
2418
+ const params = ["target", "key", "descriptor"].map((name) => ({
2419
+ localId: name,
2420
+ name,
2421
+ type: DYN,
2422
+ }));
2423
+ const target = varRef("target", DYN, loc);
2424
+ const key = varRef("key", DYN, loc);
2425
+ const descriptor = varRef("descriptor", DYN, loc);
2426
+ this.descriptorHelper = {
2427
+ name: "%dyn.class.defineProperty",
2428
+ params,
2429
+ returnType: DYN,
2430
+ locals: params.map((param) => ({
2431
+ id: param.localId,
2432
+ name: param.name,
2204
2433
  type: DYN,
2205
- }));
2206
- const target = varRef("target", DYN, loc);
2207
- const key = varRef("key", DYN, loc);
2208
- const descriptor = varRef("descriptor", DYN, loc);
2209
- this.descriptorHelper = {
2210
- name: "%dyn.class.defineProperty",
2211
- params,
2212
- returnType: DYN,
2213
- locals: params.map((param) => ({
2214
- id: param.localId,
2215
- name: param.name,
2216
- type: DYN,
2217
- mutable: false,
2218
- })),
2219
- body: [
2220
- {
2221
- kind: "if",
2222
- cond: { kind: "dynTest", test: "symbol", value: key, type: BOOL, loc },
2223
- then: [
2224
- {
2225
- kind: "exprStmt",
2226
- expr: {
2227
- ...expr,
2228
- args: [
2229
- {
2230
- kind: "call",
2231
- callee: this.propertyBag.name,
2232
- args: [target],
2233
- type: DYN,
2234
- loc,
2235
- },
2236
- key,
2237
- descriptor,
2238
- ],
2239
- },
2240
- loc,
2434
+ mutable: false,
2435
+ })),
2436
+ body: [
2437
+ {
2438
+ kind: "if",
2439
+ cond: { kind: "dynTest", test: "symbol", value: key, type: BOOL, loc },
2440
+ then: [
2441
+ {
2442
+ kind: "exprStmt",
2443
+ expr: {
2444
+ ...expr,
2445
+ args: [
2446
+ {
2447
+ kind: "call",
2448
+ callee: this.propertyBag.name,
2449
+ args: [target],
2450
+ type: DYN,
2451
+ loc,
2452
+ },
2453
+ key,
2454
+ descriptor,
2455
+ ],
2241
2456
  },
2242
- { kind: "return", value: target, loc },
2243
- ],
2244
- else_: null,
2245
- loc,
2246
- },
2247
- { kind: "return", value: { ...expr, args: [target, key, descriptor] }, loc },
2248
- ],
2249
- loc,
2250
- };
2251
- this.generated.add(this.descriptorHelper);
2252
- lowerer.liftedFns.push(this.descriptorHelper);
2253
- changed = true;
2254
- }
2255
- return {
2256
- kind: "call",
2257
- callee: this.descriptorHelper.name,
2258
- args: expr.args,
2259
- type: DYN,
2457
+ loc,
2458
+ },
2459
+ { kind: "return", value: target, loc },
2460
+ ],
2461
+ else_: null,
2462
+ loc,
2463
+ },
2464
+ { kind: "return", value: { ...expr, args: [target, key, descriptor] }, loc },
2465
+ ],
2260
2466
  loc,
2261
2467
  };
2468
+ this.generated.add(this.descriptorHelper);
2469
+ lowerer.liftedFns.push(this.descriptorHelper);
2470
+ changed = true;
2262
2471
  }
2263
- if (expr.kind === "dynKeyGet" && expr.value.kind === "dynObjLit")
2264
- return expr;
2265
- const reflectRead = expr.kind === "libCall" && expr.fn === "dyn.reflectGet" ? expr : null;
2266
- const reflectWrite = expr.kind === "libCall" && expr.fn === "dyn.reflectSet" ? expr : null;
2267
- const reflect = !!reflectRead || !!reflectWrite;
2268
- const computedRead = reflectRead
2269
- ? {
2270
- kind: "dynKeyGet",
2271
- value: reflectRead.args[0],
2272
- key: reflectRead.args[1],
2273
- type: DYN,
2274
- loc: expr.loc,
2275
- }
2276
- : expr.kind === "dynKeyGet" && expr.key.kind !== "strLit"
2277
- ? expr
2278
- : null;
2279
- const computedWrite = reflectWrite
2280
- ? {
2281
- ...reflectWrite,
2282
- fn: "dyn.keySetComputed",
2283
- args: reflectWrite.args.slice(0, 3),
2284
- type: VOID,
2285
- }
2286
- : expr.kind === "libCall" &&
2287
- (expr.fn === "dyn.keySetComputed" ||
2288
- (expr.fn === "dyn.keySet" && expr.args[1]?.kind !== "strLit"))
2289
- ? expr
2290
- : null;
2291
- const computedProbe = expr.kind === "libCall" &&
2292
- [
2293
- "dyn.hasKeyComputed",
2294
- "dyn.hasOwnComputed",
2295
- "dyn.propertyIsEnumerableComputed",
2296
- ].includes(expr.fn)
2472
+ return {
2473
+ kind: "call",
2474
+ callee: this.descriptorHelper.name,
2475
+ args: expr.args,
2476
+ type: DYN,
2477
+ loc,
2478
+ };
2479
+ }
2480
+ if (expr.kind === "dynKeyGet" && expr.value.kind === "dynObjLit")
2481
+ return expr;
2482
+ const reflectRead = expr.kind === "libCall" && expr.fn === "dyn.reflectGet" ? expr : null;
2483
+ const reflectWrite = expr.kind === "libCall" && expr.fn === "dyn.reflectSet" ? expr : null;
2484
+ const reflect = !!reflectRead || !!reflectWrite;
2485
+ const computedRead = reflectRead
2486
+ ? {
2487
+ kind: "dynKeyGet",
2488
+ value: reflectRead.args[0],
2489
+ key: reflectRead.args[1],
2490
+ type: DYN,
2491
+ loc: expr.loc,
2492
+ }
2493
+ : expr.kind === "dynKeyGet" && expr.key.kind !== "strLit"
2297
2494
  ? expr
2298
2495
  : null;
2299
- if (computedRead || computedWrite || computedProbe) {
2300
- const probe = computedProbe
2301
- ? computedProbe.fn === "dyn.hasKeyComputed"
2302
- ? "in"
2303
- : computedProbe.fn === "dyn.hasOwnComputed"
2304
- ? "own"
2305
- : "enumerable"
2306
- : undefined;
2307
- const dynamicKey = reflect ||
2308
- !!computedProbe ||
2309
- computedWrite?.fn === "dyn.keySetComputed" ||
2310
- computedRead?.key.type.kind === "dyn";
2311
- const sourceKey = keyValue(computedRead?.key ?? (computedWrite ?? computedProbe).args[1]);
2312
- const numericKey = sourceKey.type.kind === "f64" ||
2313
- (sourceKey.kind === "dynFrom" && sourceKey.value.type.kind === "f64") ||
2314
- (sourceKey.kind === "toString" && sourceKey.operand.type.kind === "f64");
2315
- // `value[i]` with a number `i`: the helper takes the number and
2316
- // reads a dense checked array element directly, formatting the
2317
- // property name only when that does not apply.
2318
- const indexKey = computedRead &&
2319
- !reflect &&
2320
- !dynamicKey &&
2321
- !computedRead.optional &&
2322
- computedRead.key.kind === "toString" &&
2323
- computedRead.key.operand.type.kind === "f64"
2324
- ? computedRead.key
2325
- : null;
2326
- // A sloppy-mode write ignores a refused assignment
2327
- // (sloppyDynamicWrites), so its sites share their own helper,
2328
- // whose write takes the first such site's source range.
2329
- const sloppyWrite = !!computedWrite && !reflect && isSloppyAt(lowerer, computedWrite.loc);
2330
- const key = JSON.stringify([
2331
- !!computedWrite,
2332
- computedRead?.optional ?? false,
2333
- dynamicKey,
2334
- probe,
2335
- numericKey,
2336
- reflect,
2337
- !!indexKey,
2338
- ...(sloppyWrite ? ["sloppy"] : []),
2339
- ]);
2340
- let dispatch = this.computed.get(key);
2341
- if (!dispatch) {
2342
- const loc = expr.loc;
2343
- const params = [
2344
- { localId: "p.0", name: "value", type: DYN },
2345
- indexKey
2346
- ? { localId: "p.index", name: "index", type: F64 }
2347
- : { localId: "p.key", name: "key", type: dynamicKey ? DYN : STRING },
2348
- ...(computedWrite ? [{ localId: "p.1", name: "stored", type: DYN }] : []),
2349
- ...(reflect ? [{ localId: "p.reflectReceiver", name: "receiver", type: DYN }] : []),
2350
- ];
2351
- const keyLocal = dynamicKey ? "key.string" : "p.key";
2352
- const bag = computedWrite
2496
+ const computedWrite = reflectWrite
2497
+ ? {
2498
+ ...reflectWrite,
2499
+ fn: "dyn.keySetComputed",
2500
+ args: reflectWrite.args.slice(0, 3),
2501
+ type: VOID,
2502
+ }
2503
+ : expr.kind === "libCall" &&
2504
+ (expr.fn === "dyn.keySetComputed" ||
2505
+ (expr.fn === "dyn.keySet" && expr.args[1]?.kind !== "strLit"))
2506
+ ? expr
2507
+ : null;
2508
+ const computedProbe = expr.kind === "libCall" &&
2509
+ ["dyn.hasKeyComputed", "dyn.hasOwnComputed", "dyn.propertyIsEnumerableComputed"].includes(expr.fn)
2510
+ ? expr
2511
+ : null;
2512
+ if (computedRead || computedWrite || computedProbe) {
2513
+ const probe = computedProbe
2514
+ ? computedProbe.fn === "dyn.hasKeyComputed"
2515
+ ? "in"
2516
+ : computedProbe.fn === "dyn.hasOwnComputed"
2517
+ ? "own"
2518
+ : "enumerable"
2519
+ : undefined;
2520
+ const dynamicKey = reflect ||
2521
+ !!computedProbe ||
2522
+ computedWrite?.fn === "dyn.keySetComputed" ||
2523
+ computedRead?.key.type.kind === "dyn";
2524
+ const sourceKey = keyValue(computedRead?.key ?? (computedWrite ?? computedProbe).args[1]);
2525
+ const numericKey = sourceKey.type.kind === "f64" ||
2526
+ (sourceKey.kind === "dynFrom" && sourceKey.value.type.kind === "f64") ||
2527
+ (sourceKey.kind === "toString" && sourceKey.operand.type.kind === "f64");
2528
+ // `value[i]` with a number `i`: the helper takes the number and
2529
+ // reads a dense checked array element directly, formatting the
2530
+ // property name only when that does not apply.
2531
+ const indexKey = computedRead &&
2532
+ !reflect &&
2533
+ !dynamicKey &&
2534
+ !computedRead.optional &&
2535
+ computedRead.key.kind === "toString" &&
2536
+ computedRead.key.operand.type.kind === "f64"
2537
+ ? computedRead.key
2538
+ : null;
2539
+ // A sloppy-mode write ignores a refused assignment
2540
+ // (sloppyDynamicWrites), so its sites share their own helper,
2541
+ // whose write takes the first such site's source range.
2542
+ const sloppyWrite = !!computedWrite && !reflect && isSloppyAt(lowerer, computedWrite.loc);
2543
+ const key = JSON.stringify([
2544
+ !!computedWrite,
2545
+ computedRead?.optional ?? false,
2546
+ dynamicKey,
2547
+ probe,
2548
+ numericKey,
2549
+ reflect,
2550
+ !!indexKey,
2551
+ ...(sloppyWrite ? ["sloppy"] : []),
2552
+ ]);
2553
+ let dispatch = this.computed.get(key);
2554
+ if (!dispatch) {
2555
+ const loc = expr.loc;
2556
+ const params = [
2557
+ { localId: "p.0", name: "value", type: DYN },
2558
+ indexKey
2559
+ ? { localId: "p.index", name: "index", type: F64 }
2560
+ : { localId: "p.key", name: "key", type: dynamicKey ? DYN : STRING },
2561
+ ...(computedWrite ? [{ localId: "p.1", name: "stored", type: DYN }] : []),
2562
+ ...(reflect ? [{ localId: "p.reflectReceiver", name: "receiver", type: DYN }] : []),
2563
+ ];
2564
+ const keyLocal = dynamicKey ? "key.string" : "p.key";
2565
+ const bag = computedWrite
2566
+ ? {
2567
+ kind: "call",
2568
+ callee: this.propertyBag.name,
2569
+ args: [varRef("p.0", DYN, loc)],
2570
+ type: DYN,
2571
+ loc,
2572
+ }
2573
+ : this.readPropertyBagOrEmpty(lowerer, varRef("p.0", DYN, loc), loc);
2574
+ const reflectionFallback = (target, property) => ({
2575
+ kind: "libCall",
2576
+ fn: computedWrite ? "dyn.reflectSet" : "dyn.reflectGet",
2577
+ args: [
2578
+ target,
2579
+ lowerer.coerceToExpected(property, DYN),
2580
+ ...(computedWrite ? [varRef("p.1", DYN, loc)] : []),
2581
+ varRef("p.reflectReceiver", DYN, loc),
2582
+ ],
2583
+ type: computedWrite ? BOOL : DYN,
2584
+ loc,
2585
+ });
2586
+ const fallback = reflect
2587
+ ? reflectionFallback(bag, varRef(keyLocal, STRING, loc))
2588
+ : computedProbe
2353
2589
  ? {
2354
- kind: "call",
2355
- callee: this.propertyBag.name,
2356
- args: [varRef("p.0", DYN, loc)],
2357
- type: DYN,
2358
- loc,
2590
+ ...computedProbe,
2591
+ fn: probe === "in"
2592
+ ? "dyn.in"
2593
+ : probe === "own"
2594
+ ? "dyn.hasOwn"
2595
+ : "dyn.propertyIsEnumerable",
2596
+ args: [bag, varRef(keyLocal, STRING, loc)],
2359
2597
  }
2360
- : this.readPropertyBagOrEmpty(lowerer, varRef("p.0", DYN, loc), loc);
2361
- const reflectionFallback = (target, property) => ({
2362
- kind: "libCall",
2363
- fn: computedWrite ? "dyn.reflectSet" : "dyn.reflectGet",
2364
- args: [
2365
- target,
2366
- lowerer.coerceToExpected(property, DYN),
2367
- ...(computedWrite ? [varRef("p.1", DYN, loc)] : []),
2368
- varRef("p.reflectReceiver", DYN, loc),
2369
- ],
2370
- type: computedWrite ? BOOL : DYN,
2371
- loc,
2372
- });
2373
- const fallback = reflect
2374
- ? reflectionFallback(bag, varRef(keyLocal, STRING, loc))
2375
- : computedProbe
2376
- ? {
2377
- ...computedProbe,
2378
- fn: probe === "in"
2379
- ? "dyn.in"
2380
- : probe === "own"
2381
- ? "dyn.hasOwn"
2382
- : "dyn.propertyIsEnumerable",
2383
- args: [bag, varRef(keyLocal, STRING, loc)],
2384
- }
2385
- : computedRead
2386
- ? { ...computedRead, value: bag, key: varRef(keyLocal, STRING, loc) }
2387
- : {
2388
- ...computedWrite,
2389
- fn: "dyn.keySet",
2390
- args: [bag, varRef(keyLocal, STRING, loc), varRef("p.1", DYN, loc)],
2391
- };
2392
- const helper = {
2393
- name: `%dyn.class.computed.${this.computed.size}`,
2394
- params,
2395
- returnType: (reflect && computedWrite) || computedProbe ? BOOL : computedWrite ? VOID : DYN,
2396
- locals: [
2397
- ...params.map((p) => ({
2398
- id: p.localId,
2399
- name: p.name,
2400
- type: p.type,
2401
- mutable: false,
2402
- })),
2403
- ...(dynamicKey || indexKey
2404
- ? [{ id: keyLocal, name: "key", type: STRING, mutable: false }]
2405
- : []),
2406
- ],
2407
- body: reflect
2408
- ? [{ kind: "return", value: fallback, loc }]
2409
- : computedWrite
2410
- ? [
2411
- { kind: "exprStmt", expr: fallback, loc },
2412
- { kind: "return", value: null, loc },
2413
- ]
2414
- : [{ kind: "return", value: fallback, loc }],
2415
- loc,
2416
- ...(numericKey && computedRead && !reflect && !dynamicKey
2417
- ? { fastRead: "index" }
2418
- : {}),
2419
- };
2420
- if (dynamicKey)
2421
- helper.body.unshift({
2422
- kind: "if",
2423
- cond: {
2424
- kind: "dynTest",
2425
- test: "symbol",
2426
- value: varRef("p.key", DYN, loc),
2427
- type: BOOL,
2428
- loc,
2429
- },
2430
- then: reflect
2598
+ : computedRead
2599
+ ? { ...computedRead, value: bag, key: varRef(keyLocal, STRING, loc) }
2600
+ : {
2601
+ ...computedWrite,
2602
+ fn: "dyn.keySet",
2603
+ args: [bag, varRef(keyLocal, STRING, loc), varRef("p.1", DYN, loc)],
2604
+ };
2605
+ const helper = {
2606
+ name: `%dyn.class.computed.${this.computed.size}`,
2607
+ params,
2608
+ returnType: (reflect && computedWrite) || computedProbe ? BOOL : computedWrite ? VOID : DYN,
2609
+ locals: [
2610
+ ...params.map((p) => ({
2611
+ id: p.localId,
2612
+ name: p.name,
2613
+ type: p.type,
2614
+ mutable: false,
2615
+ })),
2616
+ ...(dynamicKey || indexKey
2617
+ ? [{ id: keyLocal, name: "key", type: STRING, mutable: false }]
2618
+ : []),
2619
+ ],
2620
+ body: reflect
2621
+ ? [{ kind: "return", value: fallback, loc }]
2622
+ : computedWrite
2623
+ ? [
2624
+ { kind: "exprStmt", expr: fallback, loc },
2625
+ { kind: "return", value: null, loc },
2626
+ ]
2627
+ : [{ kind: "return", value: fallback, loc }],
2628
+ loc,
2629
+ ...(numericKey && computedRead && !reflect && !dynamicKey
2630
+ ? { fastRead: "index" }
2631
+ : {}),
2632
+ };
2633
+ if (dynamicKey)
2634
+ helper.body.unshift({
2635
+ kind: "if",
2636
+ cond: {
2637
+ kind: "dynTest",
2638
+ test: "symbol",
2639
+ value: varRef("p.key", DYN, loc),
2640
+ type: BOOL,
2641
+ loc,
2642
+ },
2643
+ then: reflect
2644
+ ? [
2645
+ {
2646
+ kind: "return",
2647
+ value: reflectionFallback(bag, varRef("p.key", DYN, loc)),
2648
+ loc,
2649
+ },
2650
+ ]
2651
+ : computedProbe
2431
2652
  ? [
2432
2653
  {
2433
2654
  kind: "return",
2434
- value: reflectionFallback(bag, varRef("p.key", DYN, loc)),
2655
+ value: { ...computedProbe, args: [bag, varRef("p.key", DYN, loc)] },
2435
2656
  loc,
2436
2657
  },
2437
2658
  ]
2438
- : computedProbe
2659
+ : computedRead
2439
2660
  ? [
2440
2661
  {
2441
2662
  kind: "return",
2442
- value: { ...computedProbe, args: [bag, varRef("p.key", DYN, loc)] },
2663
+ value: {
2664
+ ...computedRead,
2665
+ value: bag,
2666
+ key: varRef("p.key", DYN, loc),
2667
+ },
2443
2668
  loc,
2444
2669
  },
2445
2670
  ]
2446
- : computedRead
2447
- ? [
2448
- {
2449
- kind: "return",
2450
- value: {
2451
- ...computedRead,
2452
- value: bag,
2453
- key: varRef("p.key", DYN, loc),
2454
- },
2455
- loc,
2456
- },
2457
- ]
2458
- : [
2459
- {
2460
- kind: "exprStmt",
2461
- expr: {
2462
- ...computedWrite,
2463
- args: [bag, varRef("p.key", DYN, loc), varRef("p.1", DYN, loc)],
2464
- },
2465
- loc,
2671
+ : [
2672
+ {
2673
+ kind: "exprStmt",
2674
+ expr: {
2675
+ ...computedWrite,
2676
+ args: [bag, varRef("p.key", DYN, loc), varRef("p.1", DYN, loc)],
2466
2677
  },
2467
- { kind: "return", value: null, loc },
2468
- ],
2469
- else_: null,
2678
+ loc,
2679
+ },
2680
+ { kind: "return", value: null, loc },
2681
+ ],
2682
+ else_: null,
2683
+ loc,
2684
+ }, {
2685
+ kind: "if",
2686
+ cond: {
2687
+ kind: "dynTest",
2688
+ test: "nullish",
2689
+ value: varRef("p.0", DYN, loc),
2690
+ type: BOOL,
2470
2691
  loc,
2471
- }, {
2472
- kind: "if",
2473
- cond: {
2474
- kind: "dynTest",
2475
- test: "nullish",
2476
- value: varRef("p.0", DYN, loc),
2477
- type: BOOL,
2478
- loc,
2479
- },
2480
- then: [
2481
- ...(reflect
2692
+ },
2693
+ then: [
2694
+ ...(reflect
2695
+ ? [
2696
+ {
2697
+ kind: "return",
2698
+ value: reflectionFallback(varRef("p.0", DYN, loc), varRef("p.key", DYN, loc)),
2699
+ loc,
2700
+ },
2701
+ ]
2702
+ : computedProbe
2482
2703
  ? [
2483
2704
  {
2484
2705
  kind: "return",
2485
- value: reflectionFallback(varRef("p.0", DYN, loc), varRef("p.key", DYN, loc)),
2706
+ value: {
2707
+ ...computedProbe,
2708
+ args: [varRef("p.0", DYN, loc), varRef("p.key", DYN, loc)],
2709
+ },
2486
2710
  loc,
2487
2711
  },
2488
2712
  ]
2489
- : computedProbe
2713
+ : computedRead
2490
2714
  ? [
2491
2715
  {
2492
2716
  kind: "return",
2493
2717
  value: {
2494
- ...computedProbe,
2495
- args: [varRef("p.0", DYN, loc), varRef("p.key", DYN, loc)],
2718
+ ...computedRead,
2719
+ value: varRef("p.0", DYN, loc),
2720
+ key: varRef("p.key", DYN, loc),
2496
2721
  },
2497
2722
  loc,
2498
2723
  },
2499
2724
  ]
2500
- : computedRead
2501
- ? [
2502
- {
2503
- kind: "return",
2504
- value: {
2505
- ...computedRead,
2506
- value: varRef("p.0", DYN, loc),
2507
- key: varRef("p.key", DYN, loc),
2508
- },
2509
- loc,
2510
- },
2511
- ]
2512
- : [
2513
- {
2514
- kind: "exprStmt",
2515
- expr: {
2516
- ...computedWrite,
2517
- args: [
2518
- varRef("p.0", DYN, loc),
2519
- varRef("p.key", DYN, loc),
2520
- varRef("p.1", DYN, loc),
2521
- ],
2522
- },
2523
- loc,
2524
- },
2525
- { kind: "return", value: null, loc },
2526
- ]),
2527
- ],
2528
- else_: null,
2529
- loc,
2530
- }, {
2531
- kind: "varDecl",
2532
- localId: keyLocal,
2533
- init: {
2534
- kind: "libCall",
2535
- fn: "dyn.toStringCoerce",
2536
- args: [varRef("p.key", DYN, loc)],
2537
- type: STRING,
2538
- loc,
2539
- },
2540
- loc,
2541
- });
2542
- if (indexKey) {
2543
- // An integer index below a checked array's length names an
2544
- // element (-0 included: its property name is "0"); dyn.arrLen
2545
- // answers 0 for every other kind. Holes keep dyn.arrAt's
2546
- // ordinary named lookup.
2547
- const index = varRef("p.index", F64, loc);
2548
- const elementRead = {
2549
- kind: "if",
2550
- cond: { kind: "libCall", fn: "number.isInteger", args: [index], type: BOOL, loc },
2551
- then: [
2552
- {
2553
- kind: "if",
2554
- cond: {
2555
- kind: "bin",
2556
- op: ">=",
2557
- left: index,
2558
- right: { kind: "numLit", value: 0, type: F64, loc },
2559
- type: BOOL,
2560
- loc,
2561
- },
2562
- then: [
2563
- {
2564
- kind: "if",
2565
- cond: {
2566
- kind: "bin",
2567
- op: "<",
2568
- left: index,
2569
- right: {
2570
- kind: "libCall",
2571
- fn: "dyn.arrLen",
2572
- args: [varRef("p.0", DYN, loc)],
2573
- type: F64,
2574
- loc,
2575
- },
2576
- type: BOOL,
2577
- loc,
2578
- },
2579
- then: [
2580
- {
2581
- kind: "return",
2582
- value: {
2583
- kind: "libCall",
2584
- fn: "dyn.arrAt",
2585
- args: [varRef("p.0", DYN, loc), index],
2586
- type: DYN,
2587
- loc,
2588
- },
2589
- loc,
2590
- },
2591
- ],
2592
- else_: null,
2593
- loc,
2594
- },
2595
- ],
2596
- else_: null,
2597
- loc,
2598
- },
2599
- ],
2600
- else_: null,
2601
- loc,
2602
- };
2603
- helper.body.unshift(elementRead, {
2604
- kind: "varDecl",
2605
- localId: keyLocal,
2606
- init: { ...indexKey, operand: index },
2607
- loc,
2608
- });
2609
- }
2610
- dispatch = {
2611
- write: !!computedWrite,
2612
- reflect,
2613
- fn: helper,
2614
- classes: new Set(),
2615
- keyLocal,
2616
- branchIndex: dynamicKey ? 3 : indexKey ? 2 : 0,
2617
- dynamicKey,
2618
- numericKey,
2619
- probe,
2620
- };
2621
- this.computed.set(key, dispatch);
2622
- this.generated.add(helper);
2623
- lowerer.liftedFns.push(helper);
2624
- changed = true;
2625
- }
2626
- return {
2627
- kind: "call",
2628
- callee: dispatch.fn.name,
2629
- args: reflect
2630
- ? (reflectRead ?? reflectWrite).args
2631
- : computedRead
2632
- ? [computedRead.value, indexKey ? indexKey.operand : computedRead.key]
2633
- : (computedWrite ?? computedProbe).args,
2634
- type: dispatch.fn.returnType,
2635
- loc: expr.loc,
2636
- };
2637
- }
2638
- const read = expr.kind === "dynKeyGet" && expr.key.kind === "strLit" ? expr : null;
2639
- const write = expr.kind === "libCall" && expr.fn === "dyn.keySet" && expr.args[1]?.kind === "strLit"
2640
- ? expr
2641
- : null;
2642
- const name = read?.key.kind === "strLit"
2643
- ? read.key.value
2644
- : write?.args[1]?.kind === "strLit"
2645
- ? write.args[1].value
2646
- : null;
2647
- if (name !== null) {
2648
- const key = JSON.stringify([name, !!write, read?.optional ?? false]);
2649
- let dispatch = this.properties.get(key);
2650
- if (!dispatch) {
2651
- const loc = expr.loc;
2652
- const params = (write ? [0, 1] : [0]).map((i) => ({
2653
- localId: `p.${i}`,
2654
- name: `p${i}`,
2655
- type: DYN,
2656
- }));
2657
- const instanceBag = read
2658
- ? this.readPropertyBagOrEmpty(lowerer, varRef("p.0", DYN, loc), loc)
2659
- : {
2660
- kind: "call",
2661
- callee: this.propertyBag.name,
2662
- args: [varRef("p.0", DYN, loc)],
2663
- type: DYN,
2664
- loc,
2665
- };
2666
- const bag = read && !["name", "length", "apply"].includes(name)
2667
- ? {
2668
- kind: "call",
2669
- callee: this.constructorPropertyBag(lowerer, loc).name,
2670
- args: [instanceBag],
2671
- type: DYN,
2672
- loc,
2673
- }
2674
- : instanceBag;
2675
- // A read compares the bag with the receiver and then reads it:
2676
- // evaluate it once, so each read retains the receiver once.
2677
- const bagRead = varRef("bag.0", DYN, loc);
2678
- const bagGet = read
2679
- ? {
2680
- kind: "libCall",
2681
- fn: "dyn.bagGet",
2682
- args: [bagRead, read.key, varRef("p.0", DYN, loc)],
2683
- type: DYN,
2684
- loc,
2685
- }
2686
- : null;
2687
- // A class instance whose class chain declares no member of an
2688
- // Object.prototype method's name (classes that do answer in
2689
- // their own branches) inherits it unless an own property
2690
- // shadows it; a class constructor's static bag reads as before.
2691
- const instanceRead = read && INHERITED_OBJECT_METHODS.has(name)
2692
- ? {
2693
- kind: "ternary",
2694
- cond: {
2695
- kind: "dynTest",
2696
- test: "function",
2697
- value: varRef("p.0", DYN, loc),
2698
- type: BOOL,
2699
- loc,
2700
- },
2701
- then: bagGet,
2702
- else_: {
2703
- kind: "ternary",
2704
- cond: this.readBagHas(lowerer, "dyn.hasKey", bagRead, read.key, loc),
2705
- then: bagGet,
2706
- else_: {
2707
- kind: "libCall",
2708
- fn: "dyn.builtinMethod",
2709
- args: [{ kind: "strLit", value: "Object", type: STRING, loc }, read.key],
2710
- type: DYN,
2711
- loc,
2712
- },
2713
- type: DYN,
2714
- loc,
2715
- },
2716
- type: DYN,
2717
- loc,
2718
- }
2719
- : bagGet;
2720
- const fallback = read
2721
- ? {
2722
- kind: "ternary",
2723
- cond: {
2724
- kind: "dynScalarEq",
2725
- left: bagRead,
2726
- right: varRef("p.0", DYN, loc),
2727
- type: BOOL,
2728
- loc,
2729
- },
2730
- then: { ...read, value: bagRead },
2731
- else_: instanceRead,
2732
- type: DYN,
2733
- loc,
2734
- }
2735
- : { ...write, args: [bag, write.args[1], varRef("p.1", DYN, loc)] };
2736
- const helper = {
2737
- name: `%dyn.class.property.${this.properties.size}`,
2738
- params,
2739
- returnType: write ? VOID : DYN,
2740
- locals: [
2741
- ...params.map((p) => ({
2742
- id: p.localId,
2743
- name: p.name,
2744
- type: DYN,
2745
- mutable: false,
2746
- })),
2747
- ...(read ? [{ id: "bag.0", name: "bag", type: DYN, mutable: false }] : []),
2748
- ],
2749
- body: write
2750
- ? [
2751
- { kind: "exprStmt", expr: fallback, loc },
2752
- { kind: "return", value: null, loc },
2753
- ]
2754
- : [
2755
- { kind: "varDecl", localId: "bag.0", init: bag, loc },
2756
- {
2757
- kind: "return",
2758
- // Primitives answer their wrapper constructors.
2759
- value: name === "constructor"
2760
- ? primitiveConstructorOr(lowerer, varRef("p.0", DYN, loc), fallback, loc)
2761
- : fallback,
2762
- loc,
2763
- },
2764
- ],
2765
- loc,
2766
- };
2767
- if (!write && name === "toString" && lowerer.classes.has("%Error")) {
2768
- const value = varRef("p.0", DYN, loc);
2769
- helper.body.unshift({
2770
- kind: "if",
2771
- cond: { kind: "dynTest", test: "error", value, type: BOOL, loc },
2772
- then: [
2773
- {
2774
- kind: "return",
2775
- value: errorToStringMethod(lowerer, {
2776
- kind: "dynCheck",
2777
- value,
2778
- type: { kind: "object", className: "%Error" },
2779
- loc,
2780
- }),
2781
- loc,
2782
- },
2783
- ],
2784
- else_: null,
2725
+ : [
2726
+ {
2727
+ kind: "exprStmt",
2728
+ expr: {
2729
+ ...computedWrite,
2730
+ args: [
2731
+ varRef("p.0", DYN, loc),
2732
+ varRef("p.key", DYN, loc),
2733
+ varRef("p.1", DYN, loc),
2734
+ ],
2735
+ },
2736
+ loc,
2737
+ },
2738
+ { kind: "return", value: null, loc },
2739
+ ]),
2740
+ ],
2741
+ else_: null,
2742
+ loc,
2743
+ }, {
2744
+ kind: "varDecl",
2745
+ localId: keyLocal,
2746
+ init: {
2747
+ kind: "libCall",
2748
+ fn: "dyn.toStringCoerce",
2749
+ args: [varRef("p.key", DYN, loc)],
2750
+ type: STRING,
2785
2751
  loc,
2786
- });
2787
- }
2788
- const receiverAccess = read
2789
- ? [{ kind: "return", value: { ...read, value: varRef("p.0", DYN, loc) }, loc }]
2790
- : [
2752
+ },
2753
+ loc,
2754
+ });
2755
+ if (indexKey) {
2756
+ // An integer index below a checked array's length names an
2757
+ // element (-0 included: its property name is "0"); dyn.arrLen
2758
+ // answers 0 for every other kind. Holes keep dyn.arrAt's
2759
+ // ordinary named lookup.
2760
+ const index = varRef("p.index", F64, loc);
2761
+ const elementRead = {
2762
+ kind: "if",
2763
+ cond: { kind: "libCall", fn: "number.isInteger", args: [index], type: BOOL, loc },
2764
+ then: [
2791
2765
  {
2792
- kind: "exprStmt",
2793
- expr: {
2794
- ...write,
2795
- args: [varRef("p.0", DYN, loc), write.args[1], varRef("p.1", DYN, loc)],
2766
+ kind: "if",
2767
+ cond: {
2768
+ kind: "bin",
2769
+ op: ">=",
2770
+ left: index,
2771
+ right: { kind: "numLit", value: 0, type: F64, loc },
2772
+ type: BOOL,
2773
+ loc,
2796
2774
  },
2775
+ then: [
2776
+ {
2777
+ kind: "if",
2778
+ cond: {
2779
+ kind: "bin",
2780
+ op: "<",
2781
+ left: index,
2782
+ right: {
2783
+ kind: "libCall",
2784
+ fn: "dyn.arrLen",
2785
+ args: [varRef("p.0", DYN, loc)],
2786
+ type: F64,
2787
+ loc,
2788
+ },
2789
+ type: BOOL,
2790
+ loc,
2791
+ },
2792
+ then: [
2793
+ {
2794
+ kind: "return",
2795
+ value: {
2796
+ kind: "libCall",
2797
+ fn: "dyn.arrAt",
2798
+ args: [varRef("p.0", DYN, loc), index],
2799
+ type: DYN,
2800
+ loc,
2801
+ },
2802
+ loc,
2803
+ },
2804
+ ],
2805
+ else_: null,
2806
+ loc,
2807
+ },
2808
+ ],
2809
+ else_: null,
2797
2810
  loc,
2798
2811
  },
2799
- { kind: "return", value: null, loc },
2800
- ];
2801
- dispatch = {
2802
- name,
2803
- write: !!write,
2804
- fn: helper,
2805
- classes: new Set(),
2806
- ...(name !== "constructor" && name !== "toString"
2807
- ? { plain: { tail: [...helper.body], access: receiverAccess } }
2808
- : {}),
2812
+ ],
2813
+ else_: null,
2814
+ loc,
2809
2815
  };
2810
- this.properties.set(key, dispatch);
2811
- this.generated.add(helper);
2812
- lowerer.liftedFns.push(helper);
2813
- changed = true;
2816
+ helper.body.unshift(elementRead, {
2817
+ kind: "varDecl",
2818
+ localId: keyLocal,
2819
+ init: { ...indexKey, operand: index },
2820
+ loc,
2821
+ });
2814
2822
  }
2815
- return {
2816
- kind: "call",
2817
- callee: dispatch.fn.name,
2818
- args: read ? [read.value] : [write.args[0], write.args[2]],
2819
- type: dispatch.fn.returnType,
2820
- loc: expr.loc,
2823
+ dispatch = {
2824
+ write: !!computedWrite,
2825
+ reflect,
2826
+ fn: helper,
2827
+ classes: new Set(),
2828
+ keyLocal,
2829
+ branchIndex: dynamicKey ? 3 : indexKey ? 2 : 0,
2830
+ dynamicKey,
2831
+ numericKey,
2832
+ probe,
2821
2833
  };
2834
+ this.computed.set(key, dispatch);
2835
+ this.generated.add(helper);
2836
+ lowerer.liftedFns.push(helper);
2837
+ changed = true;
2822
2838
  }
2823
- const iterator = expr.kind === "libCall" &&
2824
- (expr.fn === "dyn.iterator" ||
2825
- expr.fn === "dyn.arrayFromIterator" ||
2826
- expr.fn === "dyn.asyncIteratorOpen")
2827
- ? expr
2839
+ return {
2840
+ kind: "call",
2841
+ callee: dispatch.fn.name,
2842
+ args: reflect
2843
+ ? (reflectRead ?? reflectWrite).args
2844
+ : computedRead
2845
+ ? [computedRead.value, indexKey ? indexKey.operand : computedRead.key]
2846
+ : (computedWrite ?? computedProbe).args,
2847
+ type: dispatch.fn.returnType,
2848
+ loc: expr.loc,
2849
+ };
2850
+ }
2851
+ const read = expr.kind === "dynKeyGet" && expr.key.kind === "strLit" ? expr : null;
2852
+ const write = expr.kind === "libCall" && expr.fn === "dyn.keySet" && expr.args[1]?.kind === "strLit"
2853
+ ? expr
2854
+ : null;
2855
+ const name = read?.key.kind === "strLit"
2856
+ ? read.key.value
2857
+ : write?.args[1]?.kind === "strLit"
2858
+ ? write.args[1].value
2828
2859
  : null;
2829
- // `for await` opens a class instance's [Symbol.asyncIterator]().
2830
- const asyncOpen = iterator?.fn === "dyn.asyncIteratorOpen";
2831
- const invoke = iterator
2832
- ? {
2833
- kind: "dynInvoke",
2834
- recv: iterator.args[0],
2835
- method: asyncOpen ? "sym:asyncIterator" : "sym:iterator",
2836
- calleeName: asyncOpen ? "value[Symbol.asyncIterator]" : "value[Symbol.iterator]",
2837
- args: [],
2838
- type: DYN,
2839
- loc: iterator.loc,
2840
- }
2841
- : expr.kind === "dynInvoke"
2842
- ? expr
2843
- : null;
2844
- // Static methods matter only for methods no instance answers.
2845
- const staticCandidates = (method) => [...this.boxedConstructors].some((name) => {
2846
- const info = lowerer.classes.get(name);
2847
- return info && findStaticOn(lowerer, info, method)?.method;
2848
- });
2849
- if (invoke &&
2850
- expr.kind === "dynInvoke" &&
2851
- candidates(invoke.method).length === 0 &&
2852
- !staticCandidates(invoke.method)) {
2853
- // The other receivers' call a rewrite left in place tests only
2854
- // the classes that rewrite did not.
2855
- const covered = expr.recv.kind === "varRef" ? this.getterReceivers.get(expr.recv.localId) : undefined;
2856
- const capsules = getterCapsules(invoke.method).filter((key) => !covered?.has(key));
2857
- if (capsules.length > 0)
2858
- return getterCall(fn, expr, capsules, covered);
2859
- }
2860
- if (!invoke ||
2861
- (candidates(invoke.method).length === 0 &&
2862
- !staticCandidates(invoke.method) &&
2863
- !(invoke.method === "toString" && lowerer.classes.has("%Error"))))
2864
- return expr;
2865
- const key = JSON.stringify([
2866
- invoke.method,
2867
- invoke.args.length,
2868
- iterator?.fn,
2869
- iterator?.args[1],
2870
- ]);
2871
- let dispatch = this.dispatches.get(key);
2860
+ if (name !== null) {
2861
+ const key = JSON.stringify([name, !!write, read?.optional ?? false]);
2862
+ let dispatch = this.properties.get(key);
2872
2863
  if (!dispatch) {
2873
- const params = [invoke.recv, ...invoke.args].map((_, i) => ({
2864
+ const loc = expr.loc;
2865
+ const params = (write ? [0, 1] : [0]).map((i) => ({
2874
2866
  localId: `p.${i}`,
2875
2867
  name: `p${i}`,
2876
2868
  type: DYN,
2877
2869
  }));
2878
- params.splice(1, 0, { localId: "p.callback", name: "callback", type: DYN });
2879
- iterator?.args.slice(1).forEach((argument, i) => params.push({
2880
- localId: `p.iterator.${i}`,
2881
- name: `iterator${i}`,
2882
- type: argument.type,
2883
- }));
2884
- params.push({ localId: "p.calleeName", name: "calleeName", type: STRING });
2885
- const callback = {
2886
- name: `%dyn.class.callback.${this.dispatches.size}`,
2887
- params: [params[0]],
2888
- returnType: DYN,
2889
- locals: [{ id: "p.0", name: "receiver", type: DYN, mutable: false }],
2890
- body: [{ kind: "return", value: dynUndefinedExpr(expr.loc), loc: expr.loc }],
2891
- loc: expr.loc,
2892
- };
2870
+ const instanceBag = read
2871
+ ? this.readPropertyBagOrEmpty(lowerer, varRef("p.0", DYN, loc), loc)
2872
+ : {
2873
+ kind: "call",
2874
+ callee: this.propertyBag.name,
2875
+ args: [varRef("p.0", DYN, loc)],
2876
+ type: DYN,
2877
+ loc,
2878
+ };
2879
+ const bag = read && !["name", "length", "apply"].includes(name)
2880
+ ? {
2881
+ kind: "call",
2882
+ callee: this.constructorPropertyBag(lowerer, loc).name,
2883
+ args: [instanceBag],
2884
+ type: DYN,
2885
+ loc,
2886
+ }
2887
+ : instanceBag;
2888
+ // A read compares the bag with the receiver and then reads it:
2889
+ // evaluate it once, so each read retains the receiver once.
2890
+ const bagRead = varRef("bag.0", DYN, loc);
2891
+ const bagGet = read
2892
+ ? {
2893
+ kind: "libCall",
2894
+ fn: "dyn.bagGet",
2895
+ args: [bagRead, read.key, varRef("p.0", DYN, loc)],
2896
+ type: DYN,
2897
+ loc,
2898
+ }
2899
+ : null;
2900
+ // A class instance whose class chain declares no member of an
2901
+ // Object.prototype method's name (classes that do answer in
2902
+ // their own branches) inherits it unless an own property
2903
+ // shadows it; a class constructor's static bag reads as before.
2904
+ const instanceRead = read && INHERITED_OBJECT_METHODS.has(name)
2905
+ ? {
2906
+ kind: "ternary",
2907
+ cond: {
2908
+ kind: "dynTest",
2909
+ test: "function",
2910
+ value: varRef("p.0", DYN, loc),
2911
+ type: BOOL,
2912
+ loc,
2913
+ },
2914
+ then: bagGet,
2915
+ else_: {
2916
+ kind: "ternary",
2917
+ cond: this.readBagHas(lowerer, "dyn.hasKey", bagRead, read.key, loc),
2918
+ then: bagGet,
2919
+ else_: {
2920
+ kind: "libCall",
2921
+ fn: "dyn.builtinMethod",
2922
+ args: [{ kind: "strLit", value: "Object", type: STRING, loc }, read.key],
2923
+ type: DYN,
2924
+ loc,
2925
+ },
2926
+ type: DYN,
2927
+ loc,
2928
+ },
2929
+ type: DYN,
2930
+ loc,
2931
+ }
2932
+ : bagGet;
2933
+ const fallback = read
2934
+ ? {
2935
+ kind: "ternary",
2936
+ cond: {
2937
+ kind: "dynScalarEq",
2938
+ left: bagRead,
2939
+ right: varRef("p.0", DYN, loc),
2940
+ type: BOOL,
2941
+ loc,
2942
+ },
2943
+ then: { ...read, value: bagRead },
2944
+ else_: instanceRead,
2945
+ type: DYN,
2946
+ loc,
2947
+ }
2948
+ : { ...write, args: [bag, write.args[1], varRef("p.1", DYN, loc)] };
2893
2949
  const helper = {
2894
- name: `%dyn.class.call.${this.dispatches.size}`,
2950
+ name: `%dyn.class.property.${this.properties.size}`,
2895
2951
  params,
2896
- returnType: DYN,
2897
- locals: params.map((p) => ({
2898
- id: p.localId,
2899
- name: p.name,
2900
- type: p.type,
2901
- mutable: false,
2902
- })),
2903
- body: [
2904
- {
2905
- kind: "return",
2906
- value: iterator
2907
- ? {
2908
- ...iterator,
2909
- args: [
2910
- varRef("p.0", DYN, expr.loc),
2911
- ...iterator.args
2912
- .slice(1)
2913
- .map((argument, i) => varRef(`p.iterator.${i}`, argument.type, expr.loc)),
2914
- ],
2915
- }
2916
- : {
2917
- ...invoke,
2918
- calleeNameValue: varRef("p.calleeName", STRING, expr.loc),
2919
- recv: varRef("p.0", DYN, expr.loc),
2920
- args: invoke.args.map((_, i) => varRef(`p.${i + 1}`, DYN, expr.loc)),
2921
- },
2922
- loc: expr.loc,
2923
- },
2952
+ returnType: write ? VOID : DYN,
2953
+ locals: [
2954
+ ...params.map((p) => ({
2955
+ id: p.localId,
2956
+ name: p.name,
2957
+ type: DYN,
2958
+ mutable: false,
2959
+ })),
2960
+ ...(read ? [{ id: "bag.0", name: "bag", type: DYN, mutable: false }] : []),
2924
2961
  ],
2925
- loc: expr.loc,
2962
+ body: write
2963
+ ? [
2964
+ { kind: "exprStmt", expr: fallback, loc },
2965
+ { kind: "return", value: null, loc },
2966
+ ]
2967
+ : [
2968
+ { kind: "varDecl", localId: "bag.0", init: bag, loc },
2969
+ {
2970
+ kind: "return",
2971
+ // Primitives answer their wrapper constructors.
2972
+ value: name === "constructor"
2973
+ ? primitiveConstructorOr(lowerer, varRef("p.0", DYN, loc), fallback, loc)
2974
+ : fallback,
2975
+ loc,
2976
+ },
2977
+ ],
2978
+ loc,
2926
2979
  };
2927
- if (invoke.method === "toString" && lowerer.classes.has("%Error")) {
2928
- const loc = expr.loc;
2980
+ if (!write && name === "toString" && lowerer.classes.has("%Error")) {
2929
2981
  const value = varRef("p.0", DYN, loc);
2930
2982
  helper.body.unshift({
2931
2983
  kind: "if",
@@ -2933,21 +2985,12 @@ export class ClassDynamicDispatch {
2933
2985
  then: [
2934
2986
  {
2935
2987
  kind: "return",
2936
- value: {
2937
- kind: "dynCall",
2938
- callee: errorToStringMethod(lowerer, {
2939
- kind: "dynCheck",
2940
- value,
2941
- type: { kind: "object", className: "%Error" },
2942
- loc,
2943
- }),
2944
- receiver: value,
2945
- calleeName: invoke.calleeName,
2946
- calleeNameValue: varRef("p.calleeName", STRING, loc),
2947
- args: invoke.args.map((_, i) => varRef(`p.${i + 1}`, DYN, loc)),
2948
- type: DYN,
2988
+ value: errorToStringMethod(lowerer, {
2989
+ kind: "dynCheck",
2990
+ value,
2991
+ type: { kind: "object", className: "%Error" },
2949
2992
  loc,
2950
- },
2993
+ }),
2951
2994
  loc,
2952
2995
  },
2953
2996
  ],
@@ -2955,54 +2998,237 @@ export class ClassDynamicDispatch {
2955
2998
  loc,
2956
2999
  });
2957
3000
  }
2958
- dispatch = { source: invoke, fn: helper, callback, classes: new Set() };
2959
- this.dispatches.set(key, dispatch);
3001
+ const receiverAccess = read
3002
+ ? [{ kind: "return", value: { ...read, value: varRef("p.0", DYN, loc) }, loc }]
3003
+ : [
3004
+ {
3005
+ kind: "exprStmt",
3006
+ expr: {
3007
+ ...write,
3008
+ args: [varRef("p.0", DYN, loc), write.args[1], varRef("p.1", DYN, loc)],
3009
+ },
3010
+ loc,
3011
+ },
3012
+ { kind: "return", value: null, loc },
3013
+ ];
3014
+ dispatch = {
3015
+ name,
3016
+ write: !!write,
3017
+ fn: helper,
3018
+ classes: new Set(),
3019
+ ...(name !== "constructor" && name !== "toString"
3020
+ ? { plain: { tail: [...helper.body], access: receiverAccess } }
3021
+ : {}),
3022
+ };
3023
+ this.properties.set(key, dispatch);
2960
3024
  this.generated.add(helper);
2961
- this.generated.add(callback);
2962
- lowerer.liftedFns.push(helper, callback);
3025
+ lowerer.liftedFns.push(helper);
2963
3026
  changed = true;
2964
3027
  }
2965
- // Resolve an own callback before argument effects can replace it.
2966
- const local = {
2967
- id: `%dispatch.receiver.${fn.locals.length}`,
2968
- name: "receiver",
3028
+ return {
3029
+ kind: "call",
3030
+ callee: dispatch.fn.name,
3031
+ args: read ? [read.value] : [write.args[0], write.args[2]],
3032
+ type: dispatch.fn.returnType,
3033
+ loc: expr.loc,
3034
+ };
3035
+ }
3036
+ const iterator = expr.kind === "libCall" &&
3037
+ (expr.fn === "dyn.iterator" ||
3038
+ expr.fn === "dyn.arrayFromIterator" ||
3039
+ expr.fn === "dyn.asyncIteratorOpen")
3040
+ ? expr
3041
+ : null;
3042
+ // `for await` opens a class instance's [Symbol.asyncIterator]().
3043
+ const asyncOpen = iterator?.fn === "dyn.asyncIteratorOpen";
3044
+ const invoke = iterator
3045
+ ? {
3046
+ kind: "dynInvoke",
3047
+ recv: iterator.args[0],
3048
+ method: asyncOpen ? "sym:asyncIterator" : "sym:iterator",
3049
+ calleeName: asyncOpen ? "value[Symbol.asyncIterator]" : "value[Symbol.iterator]",
3050
+ args: [],
2969
3051
  type: DYN,
2970
- mutable: false,
3052
+ loc: iterator.loc,
3053
+ }
3054
+ : expr.kind === "dynInvoke"
3055
+ ? expr
3056
+ : null;
3057
+ // Static methods matter only for methods no instance answers.
3058
+ const staticCandidates = (method) => [...this.boxedConstructors].some((name) => {
3059
+ const info = lowerer.classes.get(name);
3060
+ return info && findStaticOn(lowerer, info, method)?.method;
3061
+ });
3062
+ if (invoke &&
3063
+ expr.kind === "dynInvoke" &&
3064
+ candidates(invoke.method).length === 0 &&
3065
+ !staticCandidates(invoke.method)) {
3066
+ // The other receivers' call a rewrite left in place tests only
3067
+ // the classes that rewrite did not.
3068
+ const covered = expr.recv.kind === "varRef" ? this.getterReceivers.get(expr.recv.localId) : undefined;
3069
+ const capsules = getterCapsules(invoke.method).filter((key) => !covered?.has(key));
3070
+ if (capsules.length > 0)
3071
+ return getterCall(fn, expr, capsules, covered);
3072
+ }
3073
+ if (!invoke ||
3074
+ (candidates(invoke.method).length === 0 &&
3075
+ !staticCandidates(invoke.method) &&
3076
+ !(invoke.method === "toString" && lowerer.classes.has("%Error"))))
3077
+ return expr;
3078
+ const key = JSON.stringify([
3079
+ invoke.method,
3080
+ invoke.args.length,
3081
+ iterator?.fn,
3082
+ iterator?.args[1],
3083
+ ]);
3084
+ let dispatch = this.dispatches.get(key);
3085
+ if (!dispatch) {
3086
+ const params = [invoke.recv, ...invoke.args].map((_, i) => ({
3087
+ localId: `p.${i}`,
3088
+ name: `p${i}`,
3089
+ type: DYN,
3090
+ }));
3091
+ params.splice(1, 0, { localId: "p.callback", name: "callback", type: DYN });
3092
+ iterator?.args.slice(1).forEach((argument, i) => params.push({
3093
+ localId: `p.iterator.${i}`,
3094
+ name: `iterator${i}`,
3095
+ type: argument.type,
3096
+ }));
3097
+ params.push({ localId: "p.calleeName", name: "calleeName", type: STRING });
3098
+ const callback = {
3099
+ name: `%dyn.class.callback.${this.dispatches.size}`,
3100
+ params: [params[0]],
3101
+ returnType: DYN,
3102
+ locals: [{ id: "p.0", name: "receiver", type: DYN, mutable: false }],
3103
+ body: [{ kind: "return", value: dynUndefinedExpr(expr.loc), loc: expr.loc }],
3104
+ loc: expr.loc,
2971
3105
  };
2972
- fn.locals.push(local);
2973
- const receiver = varRef(local.id, DYN, expr.loc);
2974
- return {
2975
- kind: "seqExpr",
2976
- stmts: [{ kind: "varDecl", localId: local.id, init: invoke.recv, loc: expr.loc }],
2977
- result: {
2978
- kind: "call",
2979
- callee: dispatch.fn.name,
2980
- args: [
2981
- receiver,
3106
+ const helper = {
3107
+ name: `%dyn.class.call.${this.dispatches.size}`,
3108
+ params,
3109
+ returnType: DYN,
3110
+ locals: params.map((p) => ({
3111
+ id: p.localId,
3112
+ name: p.name,
3113
+ type: p.type,
3114
+ mutable: false,
3115
+ })),
3116
+ body: [
3117
+ {
3118
+ kind: "return",
3119
+ value: iterator
3120
+ ? {
3121
+ ...iterator,
3122
+ args: [
3123
+ varRef("p.0", DYN, expr.loc),
3124
+ ...iterator.args
3125
+ .slice(1)
3126
+ .map((argument, i) => varRef(`p.iterator.${i}`, argument.type, expr.loc)),
3127
+ ],
3128
+ }
3129
+ : {
3130
+ ...invoke,
3131
+ calleeNameValue: varRef("p.calleeName", STRING, expr.loc),
3132
+ recv: varRef("p.0", DYN, expr.loc),
3133
+ args: invoke.args.map((_, i) => varRef(`p.${i + 1}`, DYN, expr.loc)),
3134
+ },
3135
+ loc: expr.loc,
3136
+ },
3137
+ ],
3138
+ loc: expr.loc,
3139
+ };
3140
+ if (invoke.method === "toString" && lowerer.classes.has("%Error")) {
3141
+ const loc = expr.loc;
3142
+ const value = varRef("p.0", DYN, loc);
3143
+ helper.body.unshift({
3144
+ kind: "if",
3145
+ cond: { kind: "dynTest", test: "error", value, type: BOOL, loc },
3146
+ then: [
2982
3147
  {
2983
- kind: "call",
2984
- callee: dispatch.callback.name,
2985
- args: [receiver],
2986
- type: DYN,
2987
- loc: expr.loc,
2988
- },
2989
- ...invoke.args,
2990
- ...(iterator?.args.slice(1) ?? []),
2991
- invoke.calleeNameValue ?? {
2992
- kind: "strLit",
2993
- value: invoke.calleeName,
2994
- type: STRING,
2995
- loc: expr.loc,
3148
+ kind: "return",
3149
+ value: {
3150
+ kind: "dynCall",
3151
+ callee: errorToStringMethod(lowerer, {
3152
+ kind: "dynCheck",
3153
+ value,
3154
+ type: { kind: "object", className: "%Error" },
3155
+ loc,
3156
+ }),
3157
+ receiver: value,
3158
+ calleeName: invoke.calleeName,
3159
+ calleeNameValue: varRef("p.calleeName", STRING, loc),
3160
+ args: invoke.args.map((_, i) => varRef(`p.${i + 1}`, DYN, loc)),
3161
+ type: DYN,
3162
+ loc,
3163
+ },
3164
+ loc,
2996
3165
  },
2997
3166
  ],
2998
- type: DYN,
2999
- loc: expr.loc,
3000
- },
3167
+ else_: null,
3168
+ loc,
3169
+ });
3170
+ }
3171
+ dispatch = { source: invoke, fn: helper, callback, classes: new Set() };
3172
+ this.dispatches.set(key, dispatch);
3173
+ this.generated.add(helper);
3174
+ this.generated.add(callback);
3175
+ lowerer.liftedFns.push(helper, callback);
3176
+ changed = true;
3177
+ }
3178
+ // Resolve an own callback before argument effects can replace it.
3179
+ const local = {
3180
+ id: `%dispatch.receiver.${fn.locals.length}`,
3181
+ name: "receiver",
3182
+ type: DYN,
3183
+ mutable: false,
3184
+ };
3185
+ fn.locals.push(local);
3186
+ const receiver = varRef(local.id, DYN, expr.loc);
3187
+ return {
3188
+ kind: "seqExpr",
3189
+ stmts: [{ kind: "varDecl", localId: local.id, init: invoke.recv, loc: expr.loc }],
3190
+ result: {
3191
+ kind: "call",
3192
+ callee: dispatch.fn.name,
3193
+ args: [
3194
+ receiver,
3195
+ {
3196
+ kind: "call",
3197
+ callee: dispatch.callback.name,
3198
+ args: [receiver],
3199
+ type: DYN,
3200
+ loc: expr.loc,
3201
+ },
3202
+ ...invoke.args,
3203
+ ...(iterator?.args.slice(1) ?? []),
3204
+ invoke.calleeNameValue ?? {
3205
+ kind: "strLit",
3206
+ value: invoke.calleeName,
3207
+ type: STRING,
3208
+ loc: expr.loc,
3209
+ },
3210
+ ],
3001
3211
  type: DYN,
3002
3212
  loc: expr.loc,
3003
- };
3213
+ },
3214
+ type: DYN,
3215
+ loc: expr.loc,
3216
+ };
3217
+ };
3218
+ let touched = false;
3219
+ const body = transformStmtList(fn.body, {
3220
+ stmt: (stmt) => stmt,
3221
+ expr: (expr) => {
3222
+ const rewritten = rewriteExpr(expr);
3223
+ if (rewritten !== expr)
3224
+ touched = true;
3225
+ return rewritten;
3004
3226
  },
3005
3227
  });
3228
+ // A body the rewrite did not change keeps its statement list, so the
3229
+ // dispatch-site summaries the pass keeps stay valid.
3230
+ if (touched)
3231
+ fn.body = body;
3006
3232
  }
3007
3233
  for (const [target, cast] of this.checkedCasts) {
3008
3234
  for (const source of this.boxed) {
@@ -3046,6 +3272,11 @@ export class ClassDynamicDispatch {
3046
3272
  for (const dispatch of this.dispatches.values()) {
3047
3273
  for (const name of this.boxedConstructors) {
3048
3274
  const info = lowerer.classes.get(name);
3275
+ // The class value's property table answers a static its chain defines
3276
+ // there, computed names included; the declarer's method is not what
3277
+ // the class value holds.
3278
+ if (info && runtimeStaticDefines(lowerer, info, dispatch.source.method))
3279
+ continue;
3049
3280
  const found = info && findStaticOn(lowerer, info, dispatch.source.method);
3050
3281
  const key = `constructor:${name}`;
3051
3282
  if (!found?.method || dispatch.classes.has(key))
@@ -3336,6 +3567,9 @@ export class ClassDynamicDispatch {
3336
3567
  if (!dispatch.write)
3337
3568
  for (const name of this.boxedConstructors) {
3338
3569
  const info = lowerer.classes.get(name);
3570
+ // A table the chain defines the name in answers the read itself.
3571
+ if (info && runtimeStaticDefines(lowerer, info, dispatch.name))
3572
+ continue;
3339
3573
  const found = info && findStaticOn(lowerer, info, dispatch.name);
3340
3574
  const field = found?.field;
3341
3575
  const key = `constructor:${name}`;
@@ -5020,6 +5254,25 @@ export class ClassDynamicDispatch {
5020
5254
  this.guardClassTables(lowerer);
5021
5255
  if (lowerer)
5022
5256
  this.guardPropertyHelpers(lowerer);
5257
+ if (lowerer)
5258
+ this.indexClassBranches(lowerer);
5259
+ }
5260
+ /** Each generated class table tests its classes in order, one exact type
5261
+ * key test per class, so a receiver costs time linear in the program's
5262
+ * class count. Replace each run of such branches with a switch on the
5263
+ * length and last four bytes of the receiver's key: the branches
5264
+ * themselves stay, each still guarded by its key test, and the switch
5265
+ * selects the class the receiver is. Runs whose branches continue instead
5266
+ * of leaving the helper, or that hold fewer than sixty-four distinct classes,
5267
+ * keep the chain. */
5268
+ indexClassBranches(lowerer) {
5269
+ const seen = new Set();
5270
+ for (const fn of [...this.generated, ...lowerer.liftedFns]) {
5271
+ if (seen.has(fn))
5272
+ continue;
5273
+ seen.add(fn);
5274
+ fn.body = indexBranchRuns(fn.body);
5275
+ }
5023
5276
  }
5024
5277
  /** Each tracked class's bag initializer over a typed receiver (`this`),
5025
5278
  * for the per-class field-creation helpers (trackClassFieldCreation),