@scriptc/compiler 0.2.7 → 0.2.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 (385) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +2 -0
  2. package/dist/backend/llvm/alloc.d.ts +3 -0
  3. package/dist/backend/llvm/alloc.js +54 -13
  4. package/dist/backend/llvm/alloc.js.map +1 -1
  5. package/dist/backend/llvm/blocks.d.ts +9 -0
  6. package/dist/backend/llvm/blocks.js +9 -0
  7. package/dist/backend/llvm/blocks.js.map +1 -1
  8. package/dist/backend/llvm/borrowed-receivers.d.ts +7 -0
  9. package/dist/backend/llvm/borrowed-receivers.js +39 -0
  10. package/dist/backend/llvm/borrowed-receivers.js.map +1 -1
  11. package/dist/backend/llvm/call-lifetimes.d.ts +4 -1
  12. package/dist/backend/llvm/call-lifetimes.js +14 -3
  13. package/dist/backend/llvm/call-lifetimes.js.map +1 -1
  14. package/dist/backend/llvm/call-lifetimes.test.js +8 -3
  15. package/dist/backend/llvm/call-lifetimes.test.js.map +1 -1
  16. package/dist/backend/llvm/checked-narrows.d.ts +24 -0
  17. package/dist/backend/llvm/checked-narrows.js +108 -0
  18. package/dist/backend/llvm/checked-narrows.js.map +1 -0
  19. package/dist/backend/llvm/checked-narrows.test.d.ts +1 -0
  20. package/dist/backend/llvm/checked-narrows.test.js +208 -0
  21. package/dist/backend/llvm/checked-narrows.test.js.map +1 -0
  22. package/dist/backend/llvm/classes.d.ts +13 -1
  23. package/dist/backend/llvm/classes.js +26 -18
  24. package/dist/backend/llvm/classes.js.map +1 -1
  25. package/dist/backend/llvm/classes.test.js +32 -3
  26. package/dist/backend/llvm/classes.test.js.map +1 -1
  27. package/dist/backend/llvm/debug-info.d.ts +6 -2
  28. package/dist/backend/llvm/debug-info.js +11 -1
  29. package/dist/backend/llvm/debug-info.js.map +1 -1
  30. package/dist/backend/llvm/dense-array-access.test.js +89 -0
  31. package/dist/backend/llvm/dense-array-access.test.js.map +1 -1
  32. package/dist/backend/llvm/dyn.d.ts +4 -0
  33. package/dist/backend/llvm/dyn.js +31 -20
  34. package/dist/backend/llvm/dyn.js.map +1 -1
  35. package/dist/backend/llvm/emitter.d.ts +184 -11
  36. package/dist/backend/llvm/emitter.js +1189 -125
  37. package/dist/backend/llvm/emitter.js.map +1 -1
  38. package/dist/backend/llvm/emitter.test.js +21 -1
  39. package/dist/backend/llvm/emitter.test.js.map +1 -1
  40. package/dist/backend/llvm/expr-async.js +4 -4
  41. package/dist/backend/llvm/expr-async.js.map +1 -1
  42. package/dist/backend/llvm/expr-bytes.d.ts +1 -1
  43. package/dist/backend/llvm/expr-bytes.js +85 -8
  44. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  45. package/dist/backend/llvm/expr-callbacks.js +29 -21
  46. package/dist/backend/llvm/expr-callbacks.js.map +1 -1
  47. package/dist/backend/llvm/expr-calls.d.ts +5 -0
  48. package/dist/backend/llvm/expr-calls.js +55 -10
  49. package/dist/backend/llvm/expr-calls.js.map +1 -1
  50. package/dist/backend/llvm/expr-containers.d.ts +7 -1
  51. package/dist/backend/llvm/expr-containers.js +230 -27
  52. package/dist/backend/llvm/expr-containers.js.map +1 -1
  53. package/dist/backend/llvm/expr-control.js +25 -10
  54. package/dist/backend/llvm/expr-control.js.map +1 -1
  55. package/dist/backend/llvm/expr-dynamic.js +72 -21
  56. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  57. package/dist/backend/llvm/expr-island.js +3 -8
  58. package/dist/backend/llvm/expr-island.js.map +1 -1
  59. package/dist/backend/llvm/expr-primitives.js +41 -12
  60. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  61. package/dist/backend/llvm/expr-primitives.test.js +50 -2
  62. package/dist/backend/llvm/expr-primitives.test.js.map +1 -1
  63. package/dist/backend/llvm/expr-records.js +28 -14
  64. package/dist/backend/llvm/expr-records.js.map +1 -1
  65. package/dist/backend/llvm/expr-stream-bridges.js +41 -31
  66. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  67. package/dist/backend/llvm/expr-stream-callbacks.js +6 -3
  68. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
  69. package/dist/backend/llvm/layouts.d.ts +2 -1
  70. package/dist/backend/llvm/layouts.js +2 -2
  71. package/dist/backend/llvm/layouts.js.map +1 -1
  72. package/dist/backend/llvm/lib-abi.js +10 -0
  73. package/dist/backend/llvm/lib-abi.js.map +1 -1
  74. package/dist/backend/llvm/lib-filesystem.js +7 -11
  75. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  76. package/dist/backend/llvm/lib-process.js +8 -8
  77. package/dist/backend/llvm/lib-process.js.map +1 -1
  78. package/dist/backend/llvm/lib-shared.js +1 -0
  79. package/dist/backend/llvm/lib-shared.js.map +1 -1
  80. package/dist/backend/llvm/local-array-reads.js +73 -13
  81. package/dist/backend/llvm/local-array-reads.js.map +1 -1
  82. package/dist/backend/llvm/local-array-reads.test.js +7 -3
  83. package/dist/backend/llvm/local-array-reads.test.js.map +1 -1
  84. package/dist/backend/llvm/local-union-storage.js +10 -6
  85. package/dist/backend/llvm/local-union-storage.js.map +1 -1
  86. package/dist/backend/llvm/local-union-storage.test.js +3 -2
  87. package/dist/backend/llvm/local-union-storage.test.js.map +1 -1
  88. package/dist/backend/llvm/map-number-lookup.d.ts +18 -0
  89. package/dist/backend/llvm/map-number-lookup.js +62 -0
  90. package/dist/backend/llvm/map-number-lookup.js.map +1 -0
  91. package/dist/backend/llvm/map-read-lifetimes.d.ts +6 -0
  92. package/dist/backend/llvm/map-read-lifetimes.js +24 -3
  93. package/dist/backend/llvm/map-read-lifetimes.js.map +1 -1
  94. package/dist/backend/llvm/map-read-lifetimes.test.js +38 -19
  95. package/dist/backend/llvm/map-read-lifetimes.test.js.map +1 -1
  96. package/dist/backend/llvm/nullable-unions.d.ts +68 -0
  97. package/dist/backend/llvm/nullable-unions.js +132 -0
  98. package/dist/backend/llvm/nullable-unions.js.map +1 -0
  99. package/dist/backend/llvm/publish.d.ts +58 -0
  100. package/dist/backend/llvm/publish.js +286 -0
  101. package/dist/backend/llvm/publish.js.map +1 -0
  102. package/dist/backend/llvm/rebound-parameters.d.ts +12 -0
  103. package/dist/backend/llvm/rebound-parameters.js +72 -0
  104. package/dist/backend/llvm/rebound-parameters.js.map +1 -0
  105. package/dist/backend/llvm/rebound-parameters.test.d.ts +1 -0
  106. package/dist/backend/llvm/rebound-parameters.test.js +67 -0
  107. package/dist/backend/llvm/rebound-parameters.test.js.map +1 -0
  108. package/dist/backend/llvm/reference-effects.d.ts +18 -2
  109. package/dist/backend/llvm/reference-effects.js +106 -16
  110. package/dist/backend/llvm/reference-effects.js.map +1 -1
  111. package/dist/backend/llvm/reference-effects.test.js +52 -1
  112. package/dist/backend/llvm/reference-effects.test.js.map +1 -1
  113. package/dist/backend/llvm/shapes.d.ts +45 -17
  114. package/dist/backend/llvm/shapes.js +131 -53
  115. package/dist/backend/llvm/shapes.js.map +1 -1
  116. package/dist/backend/llvm/shapes.test.js +33 -8
  117. package/dist/backend/llvm/shapes.test.js.map +1 -1
  118. package/dist/backend/llvm/stack-unions.test.js +5 -2
  119. package/dist/backend/llvm/stack-unions.test.js.map +1 -1
  120. package/dist/backend/llvm/string-construction.d.ts +10 -0
  121. package/dist/backend/llvm/string-construction.js +42 -0
  122. package/dist/backend/llvm/string-construction.js.map +1 -1
  123. package/dist/backend/llvm/string-key-hash.d.ts +9 -2
  124. package/dist/backend/llvm/string-key-hash.js +20 -3
  125. package/dist/backend/llvm/string-key-hash.js.map +1 -1
  126. package/dist/backend/llvm/string-key-hash.test.js +14 -3
  127. package/dist/backend/llvm/string-key-hash.test.js.map +1 -1
  128. package/dist/backend/llvm/string-lifetimes.test.js +24 -11
  129. package/dist/backend/llvm/string-lifetimes.test.js.map +1 -1
  130. package/dist/backend/llvm/string-reads.d.ts +7 -0
  131. package/dist/backend/llvm/string-reads.js +76 -0
  132. package/dist/backend/llvm/string-reads.js.map +1 -0
  133. package/dist/backend/llvm/switch-dispatch.test.js +1 -1
  134. package/dist/backend/llvm/switch-dispatch.test.js.map +1 -1
  135. package/dist/backend/llvm/test-boxed-unions.d.ts +5 -0
  136. package/dist/backend/llvm/test-boxed-unions.js +13 -0
  137. package/dist/backend/llvm/test-boxed-unions.js.map +1 -0
  138. package/dist/backend/llvm/union-repr.d.ts +15 -0
  139. package/dist/backend/llvm/union-repr.js +89 -0
  140. package/dist/backend/llvm/union-repr.js.map +1 -0
  141. package/dist/backend/llvm/virtual-borrows.d.ts +31 -0
  142. package/dist/backend/llvm/virtual-borrows.js +82 -0
  143. package/dist/backend/llvm/virtual-borrows.js.map +1 -0
  144. package/dist/backend/llvm/walk-borrows.d.ts +43 -0
  145. package/dist/backend/llvm/walk-borrows.js +150 -0
  146. package/dist/backend/llvm/walk-borrows.js.map +1 -0
  147. package/dist/backend/llvm/walk-borrows.test.d.ts +1 -0
  148. package/dist/backend/llvm/walk-borrows.test.js +119 -0
  149. package/dist/backend/llvm/walk-borrows.test.js.map +1 -0
  150. package/dist/backend/llvm/walkers.d.ts +5 -1
  151. package/dist/backend/llvm/walkers.js +24 -21
  152. package/dist/backend/llvm/walkers.js.map +1 -1
  153. package/dist/backend/may-throw.d.ts +29 -1
  154. package/dist/backend/may-throw.js +346 -3
  155. package/dist/backend/may-throw.js.map +1 -1
  156. package/dist/backend/may-throw.test.js +113 -1
  157. package/dist/backend/may-throw.test.js.map +1 -1
  158. package/dist/backend/native/runtime-inputs.d.ts +1 -1
  159. package/dist/backend/native/runtime-inputs.js +1 -0
  160. package/dist/backend/native/runtime-inputs.js.map +1 -1
  161. package/dist/backend/native-codegen-core.d.ts +7 -5
  162. package/dist/backend/native-codegen-core.js +14 -9
  163. package/dist/backend/native-codegen-core.js.map +1 -1
  164. package/dist/backend/native-codegen.d.ts +4 -0
  165. package/dist/backend/native-codegen.js +49 -2
  166. package/dist/backend/native-codegen.js.map +1 -1
  167. package/dist/backend/native-codegen.test.js +41 -10
  168. package/dist/backend/native-codegen.test.js.map +1 -1
  169. package/dist/backend/native-tools.d.ts +2 -0
  170. package/dist/backend/native-tools.js +3 -0
  171. package/dist/backend/native-tools.js.map +1 -1
  172. package/dist/backend/publication.d.ts +28 -0
  173. package/dist/backend/publication.js +155 -0
  174. package/dist/backend/publication.js.map +1 -0
  175. package/dist/backend/publication.test.d.ts +1 -0
  176. package/dist/backend/publication.test.js +72 -0
  177. package/dist/backend/publication.test.js.map +1 -0
  178. package/dist/backend/runtime-abi.d.ts +2 -2
  179. package/dist/backend/runtime-abi.js +2 -2
  180. package/dist/backend/runtime-pack-targets.test.js +1 -1
  181. package/dist/backend/runtime-pack.test.js +1 -1
  182. package/dist/cli/command.js +70 -7
  183. package/dist/cli/command.js.map +1 -1
  184. package/dist/cli/usage.d.ts +4 -1
  185. package/dist/cli/usage.js +8 -1
  186. package/dist/cli/usage.js.map +1 -1
  187. package/dist/compile-types.d.ts +12 -3
  188. package/dist/coverage/report.d.ts +25 -2
  189. package/dist/coverage/report.js +161 -33
  190. package/dist/coverage/report.js.map +1 -1
  191. package/dist/coverage/verdict-cache.d.ts +63 -0
  192. package/dist/coverage/verdict-cache.js +193 -0
  193. package/dist/coverage/verdict-cache.js.map +1 -0
  194. package/dist/coverage/verdict-cache.test.d.ts +1 -0
  195. package/dist/coverage/verdict-cache.test.js +52 -0
  196. package/dist/coverage/verdict-cache.test.js.map +1 -0
  197. package/dist/coverage/verdict-semantic.d.ts +2 -0
  198. package/dist/coverage/verdict-semantic.js +24 -0
  199. package/dist/coverage/verdict-semantic.js.map +1 -0
  200. package/dist/coverage/verdict-startup.d.ts +15 -0
  201. package/dist/coverage/verdict-startup.js +66 -0
  202. package/dist/coverage/verdict-startup.js.map +1 -0
  203. package/dist/diagnostics/diagnostic.d.ts +29 -1
  204. package/dist/diagnostics/diagnostic.js +74 -4
  205. package/dist/diagnostics/diagnostic.js.map +1 -1
  206. package/dist/diagnostics/envelope.d.ts +130 -0
  207. package/dist/diagnostics/envelope.js +257 -0
  208. package/dist/diagnostics/envelope.js.map +1 -0
  209. package/dist/diagnostics/envelope.test.d.ts +1 -0
  210. package/dist/diagnostics/envelope.test.js +91 -0
  211. package/dist/diagnostics/envelope.test.js.map +1 -0
  212. package/dist/diagnostics/render.d.ts +3 -0
  213. package/dist/diagnostics/render.js +13 -2
  214. package/dist/diagnostics/render.js.map +1 -1
  215. package/dist/executable/prepare.d.ts +4 -0
  216. package/dist/executable/prepare.js +7 -1
  217. package/dist/executable/prepare.js.map +1 -1
  218. package/dist/frontend/analysis.js +1 -0
  219. package/dist/frontend/analysis.js.map +1 -1
  220. package/dist/frontend/lowering/array-values.d.ts +7 -0
  221. package/dist/frontend/lowering/array-values.js +120 -4
  222. package/dist/frontend/lowering/array-values.js.map +1 -1
  223. package/dist/frontend/lowering/builtins/numbers.js +29 -1
  224. package/dist/frontend/lowering/builtins/numbers.js.map +1 -1
  225. package/dist/frontend/lowering/builtins/process.d.ts +4 -0
  226. package/dist/frontend/lowering/builtins/process.js +10 -0
  227. package/dist/frontend/lowering/builtins/process.js.map +1 -1
  228. package/dist/frontend/lowering/builtins/workers.js +4 -2
  229. package/dist/frontend/lowering/builtins/workers.js.map +1 -1
  230. package/dist/frontend/lowering/class-assertions.d.ts +8 -0
  231. package/dist/frontend/lowering/class-assertions.js +217 -1
  232. package/dist/frontend/lowering/class-assertions.js.map +1 -1
  233. package/dist/frontend/lowering/class-dynamic-dispatch.js +8 -5
  234. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  235. package/dist/frontend/lowering/coercions/state.d.ts +6 -0
  236. package/dist/frontend/lowering/coercions/state.js +2 -0
  237. package/dist/frontend/lowering/coercions/state.js.map +1 -1
  238. package/dist/frontend/lowering/coercions/unions.d.ts +8 -0
  239. package/dist/frontend/lowering/coercions/unions.js +67 -2
  240. package/dist/frontend/lowering/coercions/unions.js.map +1 -1
  241. package/dist/frontend/lowering/collation-repertoire.d.ts +1 -0
  242. package/dist/frontend/lowering/collation-repertoire.js +19 -0
  243. package/dist/frontend/lowering/collation-repertoire.js.map +1 -0
  244. package/dist/frontend/lowering/construction-escapes.d.ts +38 -0
  245. package/dist/frontend/lowering/construction-escapes.js +146 -0
  246. package/dist/frontend/lowering/construction-escapes.js.map +1 -0
  247. package/dist/frontend/lowering/construction-escapes.test.d.ts +1 -0
  248. package/dist/frontend/lowering/construction-escapes.test.js +150 -0
  249. package/dist/frontend/lowering/construction-escapes.test.js.map +1 -0
  250. package/dist/frontend/lowering/containers/array-callbacks.js +81 -44
  251. package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
  252. package/dist/frontend/lowering/containers/array-construction.js +15 -2
  253. package/dist/frontend/lowering/containers/array-construction.js.map +1 -1
  254. package/dist/frontend/lowering/containers/array-methods.js +231 -12
  255. package/dist/frontend/lowering/containers/array-methods.js.map +1 -1
  256. package/dist/frontend/lowering/containers/callback-arguments.js +43 -1
  257. package/dist/frontend/lowering/containers/callback-arguments.js.map +1 -1
  258. package/dist/frontend/lowering/containers/string-and-regexp.js +7 -63
  259. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  260. package/dist/frontend/lowering/cycle-initialization.d.ts +6 -1
  261. package/dist/frontend/lowering/cycle-initialization.js +59 -33
  262. package/dist/frontend/lowering/cycle-initialization.js.map +1 -1
  263. package/dist/frontend/lowering/divergences.d.ts +9 -0
  264. package/dist/frontend/lowering/divergences.js +630 -0
  265. package/dist/frontend/lowering/divergences.js.map +1 -0
  266. package/dist/frontend/lowering/expressions/object-literals.js +40 -2
  267. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  268. package/dist/frontend/lowering/lower-calls.d.ts +5 -0
  269. package/dist/frontend/lowering/lower-calls.js +226 -157
  270. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  271. package/dist/frontend/lowering/lower-classes.d.ts +4 -0
  272. package/dist/frontend/lowering/lower-classes.js +72 -22
  273. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  274. package/dist/frontend/lowering/lower-exprs.d.ts +13 -0
  275. package/dist/frontend/lowering/lower-exprs.js +431 -107
  276. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  277. package/dist/frontend/lowering/lower-generators.d.ts +19 -13
  278. package/dist/frontend/lowering/lower-generators.js +67 -44
  279. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  280. package/dist/frontend/lowering/lower-inspect.js +3 -2
  281. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  282. package/dist/frontend/lowering/lower-island.d.ts +1 -1
  283. package/dist/frontend/lowering/lower-island.js +24 -7
  284. package/dist/frontend/lowering/lower-island.js.map +1 -1
  285. package/dist/frontend/lowering/lower-modules.js +90 -1
  286. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  287. package/dist/frontend/lowering/lower-stmts.js +36 -6
  288. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  289. package/dist/frontend/lowering/lowerer.d.ts +78 -2
  290. package/dist/frontend/lowering/lowerer.js +986 -73
  291. package/dist/frontend/lowering/lowerer.js.map +1 -1
  292. package/dist/frontend/lowering/runtime-optional-bounds.d.ts +19 -0
  293. package/dist/frontend/lowering/runtime-optional-bounds.js +354 -0
  294. package/dist/frontend/lowering/runtime-optional-bounds.js.map +1 -0
  295. package/dist/frontend/lowering/runtime-optional-bounds.test.d.ts +1 -0
  296. package/dist/frontend/lowering/runtime-optional-bounds.test.js +66 -0
  297. package/dist/frontend/lowering/runtime-optional-bounds.test.js.map +1 -0
  298. package/dist/frontend/lowering/runtime-optional-elements.d.ts +117 -0
  299. package/dist/frontend/lowering/runtime-optional-elements.js +738 -0
  300. package/dist/frontend/lowering/runtime-optional-elements.js.map +1 -0
  301. package/dist/frontend/lowering/runtime-optional-guards.d.ts +36 -0
  302. package/dist/frontend/lowering/runtime-optional-guards.js +375 -0
  303. package/dist/frontend/lowering/runtime-optional-guards.js.map +1 -0
  304. package/dist/frontend/lowering/runtime-optional-guards.test.d.ts +1 -0
  305. package/dist/frontend/lowering/runtime-optional-guards.test.js +92 -0
  306. package/dist/frontend/lowering/runtime-optional-guards.test.js.map +1 -0
  307. package/dist/frontend/lowering/runtime-optional-ownership.d.ts +63 -0
  308. package/dist/frontend/lowering/runtime-optional-ownership.js +382 -0
  309. package/dist/frontend/lowering/runtime-optional-ownership.js.map +1 -0
  310. package/dist/frontend/lowering/runtime-optional-provenance.d.ts +2 -1
  311. package/dist/frontend/lowering/runtime-optional-provenance.js +2 -1
  312. package/dist/frontend/lowering/runtime-optional-provenance.js.map +1 -1
  313. package/dist/frontend/lowering/string-index-bounds.d.ts +36 -0
  314. package/dist/frontend/lowering/string-index-bounds.js +537 -0
  315. package/dist/frontend/lowering/string-index-bounds.js.map +1 -0
  316. package/dist/frontend/lowering/string-index-bounds.test.d.ts +1 -0
  317. package/dist/frontend/lowering/string-index-bounds.test.js +223 -0
  318. package/dist/frontend/lowering/string-index-bounds.test.js.map +1 -0
  319. package/dist/frontend/lowering/union-narrow.d.ts +2 -0
  320. package/dist/frontend/lowering/union-narrow.js +10 -6
  321. package/dist/frontend/lowering/union-narrow.js.map +1 -1
  322. package/dist/frontend/program-analysis.d.ts +10 -0
  323. package/dist/frontend/program-analysis.js +7 -0
  324. package/dist/frontend/program-analysis.js.map +1 -1
  325. package/dist/frontend/program.d.ts +25 -0
  326. package/dist/frontend/program.js +613 -17
  327. package/dist/frontend/program.js.map +1 -1
  328. package/dist/frontend/program.test.js +64 -1
  329. package/dist/frontend/program.test.js.map +1 -1
  330. package/dist/frontend/resolve.d.ts +6 -0
  331. package/dist/frontend/resolve.js +14 -0
  332. package/dist/frontend/resolve.js.map +1 -1
  333. package/dist/frontend/threads-import.d.ts +5 -0
  334. package/dist/frontend/threads-import.js +21 -0
  335. package/dist/frontend/threads-import.js.map +1 -0
  336. package/dist/frontend/type-mapper.d.ts +3 -0
  337. package/dist/frontend/type-mapper.js +72 -6
  338. package/dist/frontend/type-mapper.js.map +1 -1
  339. package/dist/frontend/worker-target.d.ts +4 -0
  340. package/dist/frontend/worker-target.js +8 -1
  341. package/dist/frontend/worker-target.js.map +1 -1
  342. package/dist/index.d.ts +6 -1
  343. package/dist/index.js +47 -9
  344. package/dist/index.js.map +1 -1
  345. package/dist/ir/build.d.ts +5 -0
  346. package/dist/ir/build.js +7 -0
  347. package/dist/ir/build.js.map +1 -1
  348. package/dist/ir/builtin-signatures.d.ts +1 -1
  349. package/dist/ir/builtin-signatures.js +3 -0
  350. package/dist/ir/builtin-signatures.js.map +1 -1
  351. package/dist/ir/int32-slots.d.ts +72 -0
  352. package/dist/ir/int32-slots.js +837 -0
  353. package/dist/ir/int32-slots.js.map +1 -0
  354. package/dist/ir/int32-slots.test.d.ts +1 -0
  355. package/dist/ir/int32-slots.test.js +222 -0
  356. package/dist/ir/int32-slots.test.js.map +1 -0
  357. package/dist/ir/integer-ranges.d.ts +19 -3
  358. package/dist/ir/integer-ranges.js +168 -23
  359. package/dist/ir/integer-ranges.js.map +1 -1
  360. package/dist/ir/integer-ranges.test.js +74 -2
  361. package/dist/ir/integer-ranges.test.js.map +1 -1
  362. package/dist/ir/ir.d.ts +24 -6
  363. package/dist/ir/ir.js.map +1 -1
  364. package/dist/ir/validate.js +21 -2
  365. package/dist/ir/validate.js.map +1 -1
  366. package/dist/ir/validate.test.js +39 -0
  367. package/dist/ir/validate.test.js.map +1 -1
  368. package/dist/native/cache.d.ts +3 -0
  369. package/dist/native/cache.js +49 -1
  370. package/dist/native/cache.js.map +1 -1
  371. package/dist/native/cache.test.js +21 -1
  372. package/dist/native/cache.test.js.map +1 -1
  373. package/dist/native/cli.js +1 -1
  374. package/dist/native/cli.js.map +1 -1
  375. package/dist/native/compiler.d.ts +5 -0
  376. package/dist/native/compiler.js +51 -4
  377. package/dist/native/compiler.js.map +1 -1
  378. package/dist/native/prepare.d.ts +4 -0
  379. package/dist/native/prepare.js +2 -1
  380. package/dist/native/prepare.js.map +1 -1
  381. package/dist/startup-cache.d.ts +2 -0
  382. package/dist/startup-cache.js +2 -0
  383. package/dist/startup-cache.js.map +1 -1
  384. package/package.json +20 -20
  385. package/surface-manifest.json +1 -1
@@ -2,6 +2,7 @@ import { generatorDrain } from "./iterator-adapters.js";
2
2
  import { lowerUnionEquality, tagEqualityMayMissAlias } from "./strict-equality.js";
3
3
  import { isOptionalProcessStreamProperty } from "./builtins/process.js";
4
4
  import { lowerWorkerMetadata } from "./builtins/workers.js";
5
+ import { threadsImportOf } from "../threads-import.js";
5
6
  import { dynUndefinedExpr, nodeThrowExpr, numLit, strLit, varRef } from "../../ir/build.js";
6
7
  import { InternalCompilerError } from "../../errors.js";
7
8
  import { SYMBOL_T } from "../../ir/ir.js";
@@ -17,7 +18,7 @@ import * as ts from "../ts7/adapter.js";
17
18
  import { constituentTypes } from "../ts7/checker.js";
18
19
  import { dirname } from "node:path";
19
20
  import * as posix from "node:path/posix";
20
- import { checkedClassAssertion } from "./class-assertions.js";
21
+ import { checkedClassAssertion, checkedClassUnionAssertion } from "./class-assertions.js";
21
22
  import { narrowClassUnion, narrowStoredClassValue } from "./class-unions.js";
22
23
  import { lowerUnionFieldWrite } from "./expressions/union-field-write.js";
23
24
  import { captureContextArguments } from "./function-context.js";
@@ -29,7 +30,7 @@ import { ARRAY_METHODS, builtinConstLit, builtinFenceHintOf, builtinModuleConstO
29
30
  import { UNSUPPORTED, blockedBindingUseDiag, requiresDynamicPackageDiag, unsupportedDiag, } from "../../diagnostics/diagnostic.js";
30
31
  import { PoisonError, dynFallbackType, jsFuncNameOf, neverTaintedJsType, own } from "./lowerer.js";
31
32
  import { lowerCollectionSpread } from "./containers/collection-methods.js";
32
- import { arrayValueRead, arrayValueStore, arrayValueType, lowerSafeIndexRead, tryLowerIndexTruthiness, tryLowerNumericIndexRead, } from "./array-values.js";
33
+ import { arrayValueRead, arrayValueStore, arrayValueType, lowerSafeIndexRead, tryLowerIndexTruthiness, tryLowerNumericIndexRead, lowerSafeBytesRead, } from "./array-values.js";
33
34
  import { strCharsCall } from "./containers/array-construction.js";
34
35
  import { lowerOptionalStringIndex } from "./string-index.js";
35
36
  import { tryLowerIndexedComparison } from "./indexed-comparison.js";
@@ -294,6 +295,14 @@ function lowerExprInner(lowerer, expr) {
294
295
  // traps. Sub-union assertions and non-union inners keep their
295
296
  // historic erasure (the widening sites re-tag with traps already).
296
297
  if (ts.isNonNullExpression(expr)) {
298
+ // An asserted element read forwarded into a slot that holds undefined
299
+ // (see analyzeRuntimeOptionalArrayReads) reads without the bounds trap.
300
+ if (lowerer.runtimeOptionalAssertions.has(expr) &&
301
+ ts.isElementAccessExpression(expr.expression)) {
302
+ const probe = lowerAbsenceProbe(lowerer, expr.expression);
303
+ if (probe?.type.kind === "union")
304
+ return probe;
305
+ }
297
306
  const inner = lowerer.lowerExpr(expr.expression);
298
307
  if (inner.type.kind === "union") {
299
308
  // `!` performs no runtime check: a missing array element stays
@@ -301,14 +310,20 @@ function lowerExprInner(lowerer, expr) {
301
310
  if (ts.isElementAccessExpression(expr.expression) &&
302
311
  assertedElementKeepsUndefined(lowerer, expr))
303
312
  return inner;
313
+ // A forwarded assertion whose destination was promoted to hold
314
+ // undefined (see analyzeRuntimeOptionalArrayReads), or an equality
315
+ // operand, keeps the value: `!` performs no runtime check.
316
+ const target = lowerer.mapTypeOf(lowerer.typeOf(expr));
317
+ if (lowerer.runtimeOptionalAssertions.has(expr) ||
318
+ (target?.kind === "object" && isEqualityOperand(expr)))
319
+ return inner;
304
320
  const use = runtimeOptionalUseOf(expr);
305
321
  if (runtimeOptionalAssertionErases(lowerer, expr, inner, use))
306
322
  return inner;
307
- const target = lowerer.mapTypeOf(lowerer.typeOf(expr));
308
323
  if (target && target.kind !== "union" && !typeEquals(target, inner.type)) {
309
324
  const helper = lowerer.narrowedArmHelper(inner.type.unionId, target, loc);
310
325
  if (helper) {
311
- return { kind: "call", callee: helper, args: [inner], type: target, loc };
326
+ return lowerer.checkedNarrowCall(helper, inner, target, loc);
312
327
  }
313
328
  }
314
329
  return inner;
@@ -730,7 +745,7 @@ function lowerExprInner(lowerer, expr) {
730
745
  // A known static result type fixes typeof's answer, but its producer
731
746
  // still evaluates: calls, getters, and checked reads can have effects
732
747
  // or throw. Only trivial operands may disappear.
733
- let operand = lowerer.lowerExpr(expr.expression);
748
+ let operand = deferredSlotOr(lowerer, runtimeOptionalStorageOperand(lowerer, expr.expression) ?? lowerer.lowerExpr(expr.expression));
734
749
  if (operand.type.kind === "jsval") {
735
750
  return { kind: "jsOp", op: "typeof", args: [operand], type: STRING, loc };
736
751
  }
@@ -949,13 +964,7 @@ function lowerExprInner(lowerer, expr) {
949
964
  ? lowerer.narrowedArmHelper(local.type.unionId, narrowed, loc)
950
965
  : null;
951
966
  if (helper) {
952
- return {
953
- kind: "call",
954
- callee: helper,
955
- args: [varRef(local.id, local.type, loc)],
956
- type: narrowed,
957
- loc,
958
- };
967
+ return lowerer.checkedNarrowCall(helper, varRef(local.id, local.type, loc), narrowed, loc);
959
968
  }
960
969
  }
961
970
  }
@@ -993,7 +1002,10 @@ function lowerExprInner(lowerer, expr) {
993
1002
  // that does not exist. The blocked-binding cascade names the use;
994
1003
  // without this the validator's registration check ICEs on the live
995
1004
  // reference (`@this {T}` inference — signature 07).
996
- if (lowerer.typeNamesUnregisteredClass(g.type)) {
1005
+ const unregistered = lowerer.unregisteredClassOf(g.type, new Set());
1006
+ if (unregistered !== null) {
1007
+ // The class's own rejection is the root cause the cascade names.
1008
+ lowerer.flushDeferredClass(unregistered);
997
1009
  lowerer.pushDiag(blockedBindingUseDiag(expr.text, loc));
998
1010
  throw new PoisonError();
999
1011
  }
@@ -1026,7 +1038,7 @@ function lowerExprInner(lowerer, expr) {
1026
1038
  lowerer.armTag(g.type.unionId, narrowed) >= 0) {
1027
1039
  const helper = lowerer.narrowedArmHelper(g.type.unionId, narrowed, loc);
1028
1040
  if (helper)
1029
- return { kind: "call", callee: helper, args: [ref], type: narrowed, loc };
1041
+ return lowerer.checkedNarrowCall(helper, ref, narrowed, loc);
1030
1042
  }
1031
1043
  const use = runtimeOptionalUseOf(expr);
1032
1044
  // The enclosing logical/conditional expression consumes the union
@@ -1124,6 +1136,14 @@ function lowerExprInner(lowerer, expr) {
1124
1136
  // as interned string literals; functions have no closure
1125
1137
  // representation (they lower to libCall at call sites only); members
1126
1138
  // with no lowering at all fence with the module-qualified name.
1139
+ {
1140
+ const member = threadsImportOf(lowerer.program, expr);
1141
+ // scriptc delivers published graphs by reference.
1142
+ if (member === "sharesPublishedGraphs")
1143
+ return { kind: "boolLit", value: true, type: BOOL, loc };
1144
+ if (member === "publish")
1145
+ lowerer.noLowering("publish (@scriptc/threads) as a value", expr, "call publish(value) directly");
1146
+ }
1127
1147
  {
1128
1148
  const bi = lowerer.builtinImportOf(expr);
1129
1149
  if (bi) {
@@ -3299,13 +3319,7 @@ function runtimeOptionalReceiverRead(lowerer, expr, local, property, loc) {
3299
3319
  if (!helper) {
3300
3320
  lowerer.unsupported("SC1090", expr, "a direct read from a runtime-optional capture with multiple value arms");
3301
3321
  }
3302
- return {
3303
- kind: "call",
3304
- callee: helper,
3305
- args: [varRef(local.id, local.type, loc)],
3306
- type: narrowed,
3307
- loc,
3308
- };
3322
+ return lowerer.checkedNarrowCall(helper, varRef(local.id, local.type, loc), narrowed, loc);
3309
3323
  }
3310
3324
  // A predicate can strengthen a record's fields or narrow a base class
3311
3325
  // to a subclass without changing the slot's stored value arm. Extract
@@ -3438,6 +3452,18 @@ function runtimeOptionalElementKey(expr) {
3438
3452
  return expr.text;
3439
3453
  return null;
3440
3454
  }
3455
+ /** An operand of `===`, `!==`, `==` or `!=` (through parentheses). */
3456
+ function isEqualityOperand(node) {
3457
+ let outer = node;
3458
+ while (ts.isParenthesizedExpression(outer.parent))
3459
+ outer = outer.parent;
3460
+ const parent = outer.parent;
3461
+ return (ts.isBinaryExpression(parent) &&
3462
+ (parent.operatorToken.kind === ts.SyntaxKind.EqualsEqualsEqualsToken ||
3463
+ parent.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken ||
3464
+ parent.operatorToken.kind === ts.SyntaxKind.EqualsEqualsToken ||
3465
+ parent.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsToken));
3466
+ }
3441
3467
  /** Whether `xs[i]!` lands where an absent element's undefined is
3442
3468
  * representable: array storage (a literal element, a push/unshift
3443
3469
  * argument, an element assignment — arrays record the undefined state),
@@ -3505,6 +3531,17 @@ export function lowerUnitComparison(lowerer, left, right, negated, loc) {
3505
3531
  // Two unit literals (`undefined === undefined`): statically decided.
3506
3532
  return { kind: "boolLit", value: (other.unit === unit.unit) !== negated, type: BOOL, loc };
3507
3533
  }
3534
+ const slot = lowerer.deferredFieldSlot(other);
3535
+ if (slot)
3536
+ return lowerUnitComparison(lowerer, slot, unit, negated, loc);
3537
+ // A binding the checker narrowed past the unit can still hold it at
3538
+ // runtime when its value came from an unassigned deferred-init field;
3539
+ // the stored tag answers either way.
3540
+ if (other.kind === "unionNarrow" &&
3541
+ other.value.kind === "varRef" &&
3542
+ other.value.type.kind === "union" &&
3543
+ lowerer.armTag(other.value.type.unionId, unit.type) >= 0)
3544
+ return lowerUnitComparison(lowerer, other.value, unit, negated, loc);
3508
3545
  if (other.type.kind === "union") {
3509
3546
  const tag = lowerer.armTag(other.type.unionId, unit.type);
3510
3547
  if (tag < 0) {
@@ -3612,7 +3649,7 @@ function lowerLooseNullCompare(lowerer, expr, loc) {
3612
3649
  if (!leftIsNull && right.kind !== ts.SyntaxKind.NullKeyword)
3613
3650
  return null;
3614
3651
  const otherNode = leftIsNull ? right : left;
3615
- const other = lowerer.lowerExpr(otherNode);
3652
+ const other = lowerPresenceOperand(lowerer, otherNode);
3616
3653
  if (isUnitType(other.type)) {
3617
3654
  // `null == null`, `undefined == null`: units are mutually loose-equal.
3618
3655
  return { kind: "boolLit", value: !negated, type: BOOL, loc };
@@ -3717,13 +3754,84 @@ export function lowerNullishCoalesce(lowerer, expr, loc) {
3717
3754
  parents.push(first);
3718
3755
  first = first.left;
3719
3756
  }
3720
- let result = lowerNullishPair(lowerer, first, first === expr ? loc : locOf(first), lowerAbsenceProbe(lowerer, first.left) ?? lowerer.lowerExpr(first.left));
3757
+ let result = lowerNullishPair(lowerer, first, first === expr ? loc : locOf(first), assertedPresenceOperand(lowerer, first.left));
3721
3758
  for (let i = parents.length - 1; i >= 0; i--) {
3722
3759
  const parent = parents[i];
3723
3760
  result = lowerNullishPair(lowerer, parent, parent === expr ? loc : locOf(parent), result);
3724
3761
  }
3725
3762
  return result;
3726
3763
  }
3764
+ /** The left side of `??` (see lowerPresenceOperand). The absence probe
3765
+ * reads optional storage beneath erased assertions; a union assertion that
3766
+ * narrows a stored class arm still applies its checked class view, so
3767
+ * `(node.parent as Sub | undefined) ?? node` sees the asserted arm on both
3768
+ * sides of the default. */
3769
+ function assertedPresenceOperand(lowerer, node) {
3770
+ const probe = lowerAbsenceProbe(lowerer, node);
3771
+ if (probe === null)
3772
+ return runtimeOptionalStorageOperand(lowerer, node) ?? lowerer.lowerExpr(node);
3773
+ if (probe.type.kind !== "union" && probe.type.kind !== "object")
3774
+ return probe;
3775
+ let outer = node;
3776
+ while (ts.isParenthesizedExpression(outer))
3777
+ outer = outer.expression;
3778
+ if (!ts.isAsExpression(outer) && !ts.isTypeAssertion(outer))
3779
+ return probe;
3780
+ const target = lowerer.mapTypeOf(lowerer.checker.getTypeFromTypeNode(outer.type));
3781
+ if (target?.kind !== "union" || typeEquals(target, probe.type))
3782
+ return probe;
3783
+ return checkedClassUnionAssertion(lowerer, probe, target, locOf(outer)) ?? probe;
3784
+ }
3785
+ /** Read-modify-write updates read the member first: an unassigned
3786
+ * deferred-init receiver throws Node's member-read TypeError. */
3787
+ function checkDeferredMemberReceiver(lowerer, target, access) {
3788
+ if (target.container !== "class" ||
3789
+ !ts.isPropertyAccessExpression(access) ||
3790
+ target.obj.type.kind !== "object" ||
3791
+ lowerer.deferredFieldSlot(target.obj) === null)
3792
+ return;
3793
+ target.obj =
3794
+ lowerer.runtimeOptionalPropertyReceiver(access.expression, target.obj, target.obj.type, target.field) ?? target.obj;
3795
+ }
3796
+ /** Whether evaluating `expr` cannot store anything or run other code:
3797
+ * reads, arithmetic, tests and checked extractions (which at most throw). */
3798
+ function writeFree(expr) {
3799
+ switch (expr.kind) {
3800
+ case "numLit":
3801
+ case "strLit":
3802
+ case "boolLit":
3803
+ case "unitLit":
3804
+ case "varRef":
3805
+ return true;
3806
+ case "fieldGet":
3807
+ case "recordGet":
3808
+ return writeFree(expr.obj);
3809
+ case "bin":
3810
+ case "logical":
3811
+ return writeFree(expr.left) && writeFree(expr.right);
3812
+ case "unary":
3813
+ case "toBool":
3814
+ return writeFree(expr.operand);
3815
+ case "ternary":
3816
+ return writeFree(expr.cond) && writeFree(expr.then) && writeFree(expr.else_);
3817
+ case "unionIsTag":
3818
+ case "unionNarrow":
3819
+ case "unionWrap":
3820
+ return writeFree(expr.value);
3821
+ case "libCall":
3822
+ return expr.fn === "error.nodeThrow";
3823
+ default:
3824
+ return false;
3825
+ }
3826
+ }
3827
+ /** The TypeError of a deferred-init field read that finds the field
3828
+ * unassigned where its declared type cannot hold undefined. */
3829
+ export const DEFERRED_READ_MESSAGE = "undefined is not representable in the target union (a value narrowed or asserted past it still held it)";
3830
+ /** The undefined-armed slot behind a checked deferred-init field read, or
3831
+ * the value itself (Lowerer.deferredFieldSlot). */
3832
+ function deferredSlotOr(lowerer, value) {
3833
+ return lowerer.deferredFieldSlot(value) ?? value;
3834
+ }
3727
3835
  /** A plain value read that may be runtime-optional: an unchecked element
3728
3836
  * read, or a binding, member or call that carries one. Lowering these
3729
3837
  * without a destination type is the same as lowering them into one. */
@@ -3844,6 +3952,24 @@ function lowerNullishPair(lowerer, expr, loc, left) {
3844
3952
  return nullishBranches(lowerer, left, left.type, def.arms, type, loc, () => lowerer.lowerExprExpecting(expr.right, type), (stable) => ({ kind: "call", callee: helper, args: [stable], type, loc }));
3845
3953
  }
3846
3954
  }
3955
+ // A subclass value defaulted to a base-class value (`circle ?? shape`):
3956
+ // the present arm upcasts after the original nullish test, and the
3957
+ // default lowers lazily into the base-class result.
3958
+ const present = rest.length === 1 ? rest[0] : null;
3959
+ if (present?.kind === "object" &&
3960
+ type.kind === "object" &&
3961
+ present.className !== type.className &&
3962
+ lowerer.isSubclassOf(present.className, type.className)) {
3963
+ const helper = lowerer.narrowedArmHelper(left.type.unionId, present, loc);
3964
+ if (helper !== null) {
3965
+ return nullishBranches(lowerer, left, left.type, def.arms, type, loc, () => lowerer.lowerExprExpecting(expr.right, type), (stable) => ({
3966
+ kind: "upcast",
3967
+ value: { kind: "call", callee: helper, args: [stable], type: present, loc },
3968
+ type,
3969
+ loc,
3970
+ }));
3971
+ }
3972
+ }
3847
3973
  // A default may change the union or widen its records. Test the
3848
3974
  // original tag before coercing: converting the whole left first can
3849
3975
  // lose nullish arms, and evaluating the default eagerly loses laziness.
@@ -3957,7 +4083,7 @@ export function lowerCondition(lowerer, expr) {
3957
4083
  };
3958
4084
  }
3959
4085
  }
3960
- const value = lowerAbsenceProbe(lowerer, expr) ?? lowerer.lowerExpr(expr);
4086
+ const value = lowerPresenceOperand(lowerer, expr);
3961
4087
  return (tryLowerIndexTruthiness(lowerer, value, expr, locOf(expr)) ?? lowerer.ensureBool(value, expr));
3962
4088
  }
3963
4089
  function lowerPromiseThenPresence(lowerer, access, result) {
@@ -3997,13 +4123,7 @@ function lowerPromiseThenPresence(lowerer, access, result) {
3997
4123
  const helper = lowerer.narrowedArmHelper(receiver.type.unionId, promiseType, receiver.loc);
3998
4124
  if (helper === null)
3999
4125
  return null;
4000
- receiver = {
4001
- kind: "call",
4002
- callee: helper,
4003
- args: [receiver],
4004
- type: promiseType,
4005
- loc: receiver.loc,
4006
- };
4126
+ receiver = lowerer.checkedNarrowCall(helper, receiver, promiseType, receiver.loc);
4007
4127
  }
4008
4128
  }
4009
4129
  if (receiver.type.kind === "dyn") {
@@ -4691,13 +4811,7 @@ export function lowerIntrinsicProperty(lowerer, expr) {
4691
4811
  ? lowerer.narrowedArmHelper(receiver.type.unionId, present, locOf(expr.expression))
4692
4812
  : null;
4693
4813
  receiver = helper
4694
- ? {
4695
- kind: "call",
4696
- callee: helper,
4697
- args: [receiver],
4698
- type: present,
4699
- loc: locOf(expr.expression),
4700
- }
4814
+ ? lowerer.checkedNarrowCall(helper, receiver, present, locOf(expr.expression))
4701
4815
  : lowerer.maybeNarrow(receiver, expr.expression);
4702
4816
  }
4703
4817
  // An island handle behind a typed-array .d.ts surface: the engine
@@ -4791,13 +4905,7 @@ export function lowerIntrinsicProperty(lowerer, expr) {
4791
4905
  ? lowerer.narrowedArmHelper(receiver.type.unionId, present, locOf(expr.expression))
4792
4906
  : null;
4793
4907
  receiver = helper
4794
- ? {
4795
- kind: "call",
4796
- callee: helper,
4797
- args: [receiver],
4798
- type: present,
4799
- loc: locOf(expr.expression),
4800
- }
4908
+ ? lowerer.checkedNarrowCall(helper, receiver, present, locOf(expr.expression))
4801
4909
  : lowerer.maybeNarrow(receiver, expr.expression);
4802
4910
  }
4803
4911
  // An island handle behind an array-typed .d.ts surface
@@ -5097,7 +5205,30 @@ export function lowerArrayLiteral(lowerer, expr, expected) {
5097
5205
  }
5098
5206
  lowerer.badType(expr, tsType);
5099
5207
  }
5100
- const type = mapped;
5208
+ let type = mapped;
5209
+ // An inferred array of records takes the layout of an element literal
5210
+ // whose fields widened for missing-element reads; the other elements
5211
+ // build that layout directly. An explicit destination keeps its own.
5212
+ if (!expected && type.elem.kind === "record") {
5213
+ let variant = null;
5214
+ for (const candidate of expr.elements) {
5215
+ let x = candidate;
5216
+ while (ts.isParenthesizedExpression(x))
5217
+ x = x.expression;
5218
+ if (!ts.isObjectLiteralExpression(x))
5219
+ continue;
5220
+ const probe = tryLowerExpression(lowerer, x);
5221
+ if (!probe || !lowerer.isRuntimeOptionalRecordVariant(probe.type, type.elem))
5222
+ continue;
5223
+ if (variant !== null && !typeEquals(variant, probe.type)) {
5224
+ variant = null;
5225
+ break;
5226
+ }
5227
+ variant = probe.type;
5228
+ }
5229
+ if (variant !== null)
5230
+ type = arrayOf(variant);
5231
+ }
5101
5232
  // Keep the array payload type fixed. Optional reads are stored through
5102
5233
  // arrayValueStore, which records UNDEFINED in the state byte while the
5103
5234
  // payload remains number/string/etc.; widening the array element here
@@ -5262,8 +5393,21 @@ export function lowerArrayLiteral(lowerer, expr, expected) {
5262
5393
  }
5263
5394
  const out = lowerer.declareHiddenLocal("%arrayLit", type);
5264
5395
  const outRef = varRef(out.id, type, loc);
5396
+ // Dense capacity for the elements the statements below store.
5397
+ const capacity = Math.min(elems.length - spreads.length, 1024);
5265
5398
  const body = [
5266
- { kind: "varDecl", localId: out.id, init: { kind: "arrayLit", elems: [], type, loc }, loc },
5399
+ {
5400
+ kind: "varDecl",
5401
+ localId: out.id,
5402
+ init: {
5403
+ kind: "arrayLit",
5404
+ elems: [],
5405
+ ...(capacity > 0 ? { capacity } : {}),
5406
+ type,
5407
+ loc,
5408
+ },
5409
+ loc,
5410
+ },
5267
5411
  ];
5268
5412
  const spreadSet = new Set(spreads);
5269
5413
  const currentLength = () => ({
@@ -5686,7 +5830,7 @@ export function lowerElementAccess(lowerer, expr) {
5686
5830
  ? lowerer.narrowedArmHelper(recv.type.unionId, present, locOf(expr.expression))
5687
5831
  : null;
5688
5832
  recv = helper
5689
- ? { kind: "call", callee: helper, args: [recv], type: present, loc: locOf(expr.expression) }
5833
+ ? lowerer.checkedNarrowCall(helper, recv, present, locOf(expr.expression))
5690
5834
  : lowerer.maybeNarrow(recv, expr.expression);
5691
5835
  }
5692
5836
  // A typed-array .d.ts surface whose VALUE is an island handle
@@ -5719,14 +5863,21 @@ export function lowerElementAccess(lowerer, expr) {
5719
5863
  if (index.type.kind !== "f64") {
5720
5864
  lowerer.unsupported("SC1090", expr.argumentExpression, "indexing with non-number keys");
5721
5865
  }
5722
- return {
5723
- kind: "bytesIntrinsic",
5724
- method: "get",
5725
- receiver: recv,
5726
- args: [index],
5727
- type: F64,
5728
- loc: locOf(expr),
5729
- };
5866
+ // `t[i]!` asserts presence: the numeric element read (NaN when
5867
+ // invalid). Every other read answers undefined for an invalid index,
5868
+ // like Node.
5869
+ if (ts.isNonNullExpression(expr.parent) && expr.parent.expression === expr) {
5870
+ return {
5871
+ kind: "bytesIntrinsic",
5872
+ method: "get",
5873
+ receiver: recv,
5874
+ args: [index],
5875
+ type: F64,
5876
+ loc: locOf(expr),
5877
+ invalidNaN: true,
5878
+ };
5879
+ }
5880
+ return lowerSafeBytesRead(lowerer, recv, index, locOf(expr));
5730
5881
  }
5731
5882
  // Tuple element read `t[0]`: a positional-field read of the tuple's
5732
5883
  // record shape — LITERAL indices only (the checker's per-index types
@@ -5769,13 +5920,7 @@ export function lowerElementAccess(lowerer, expr) {
5769
5920
  ? lowerer.narrowedArmHelper(obj.type.unionId, present, locOf(expr.expression))
5770
5921
  : null;
5771
5922
  obj = helper
5772
- ? {
5773
- kind: "call",
5774
- callee: helper,
5775
- args: [obj],
5776
- type: present,
5777
- loc: locOf(expr.expression),
5778
- }
5923
+ ? lowerer.checkedNarrowCall(helper, obj, present, locOf(expr.expression))
5779
5924
  : lowerer.maybeNarrow(obj, expr.expression);
5780
5925
  }
5781
5926
  const idx = tupleLiteralIndex(expr.argumentExpression);
@@ -5957,6 +6102,17 @@ export function lowerElementAccess(lowerer, expr) {
5957
6102
  const recv = lowerer.lowerExpr(expr.expression);
5958
6103
  const index = lowerOptionalNumber(lowerer, lowerer.lowerExpr(expr.argumentExpression), locOf(expr.argumentExpression), expr.argumentExpression);
5959
6104
  if (index.type.kind === "f64" && recv.type.kind === "string") {
6105
+ // A proven in-bounds integer index always names a code unit, where
6106
+ // charAt and the property read agree.
6107
+ if (lowerer.stringIndexBounds.inBounds(expr))
6108
+ return {
6109
+ kind: "strIntrinsic",
6110
+ method: "charAt",
6111
+ receiver: recv,
6112
+ args: [index],
6113
+ type: STRING,
6114
+ loc: locOf(expr),
6115
+ };
5960
6116
  return lowerOptionalStringIndex(lowerer, recv, index, lowerer.withUndefinedArm(STRING), locOf(expr));
5961
6117
  }
5962
6118
  lowerer.unsupported("SC1090", expr, "string indexing with this index/result shape (expected a number index and a string or string | undefined result)");
@@ -6020,7 +6176,7 @@ export function lowerElementAccess(lowerer, expr) {
6020
6176
  ? lowerer.narrowedArmHelper(arr.type.unionId, present, locOf(expr.expression))
6021
6177
  : null;
6022
6178
  arr = helper
6023
- ? { kind: "call", callee: helper, args: [arr], type: present, loc: locOf(expr.expression) }
6179
+ ? lowerer.checkedNarrowCall(helper, arr, present, locOf(expr.expression))
6024
6180
  : lowerer.maybeNarrow(arr, expr.expression);
6025
6181
  }
6026
6182
  // The checker sees an array but the VALUE is an island handle (an
@@ -6330,6 +6486,57 @@ function lowerRecordPropertyKey(lowerer, key, node) {
6330
6486
  }
6331
6487
  return key;
6332
6488
  }
6489
+ /** The stored value of an identifier whose storage holds an undefined arm
6490
+ * that the checker's type at this use has dropped. An assignment from an
6491
+ * unchecked indexed read narrows the declared type even though the value
6492
+ * can be absent at runtime, so presence tests (`=== undefined`, `== null`,
6493
+ * truthiness, `??`, `typeof`) read the storage tag instead of trusting
6494
+ * that narrowing. A guard-proven use answers the same way at runtime. */
6495
+ export function runtimeOptionalStorageOperand(lowerer, node) {
6496
+ let expr = node;
6497
+ while (ts.isParenthesizedExpression(expr))
6498
+ expr = expr.expression;
6499
+ if (!ts.isIdentifier(expr))
6500
+ return null;
6501
+ // Only storage that can actually receive an absent value without the
6502
+ // checker seeing it qualifies; other declared-optional bindings keep the
6503
+ // checker's assignment and guard narrowing.
6504
+ const symbol = lowerer.resolveValueSymbol(expr);
6505
+ const local = lowerer.resolveLocal(expr);
6506
+ const global = local ? undefined : lowerer.globalOf(expr);
6507
+ const root = local ? lowerer.runtimeOptionalRootOf(local) : null;
6508
+ if (root && lowerer.runtimeOptionalStorageLocals.has(root)) {
6509
+ // These locals track guards: a branch that proved presence removes
6510
+ // the binding from the active set, and its reads stay narrowed. A
6511
+ // captured binding can be reassigned between calls, so a capture
6512
+ // never inherits a guard (the identifier read's own rule).
6513
+ const captured = local.boxed === true ||
6514
+ (!!symbol && lowerer.ctx.captureBySymbol.get(symbol) === local) ||
6515
+ root !== local;
6516
+ if (!captured && !lowerer.runtimeOptionalLocals.has(root))
6517
+ return null;
6518
+ }
6519
+ else if (!(symbol && lowerer.runtimeOptionalAssignedSymbols.has(symbol)) &&
6520
+ !(symbol && lowerer.runtimeOptionalBindingTypes.has(symbol)) &&
6521
+ !(global && lowerer.isRuntimeOptionalGlobal(global)))
6522
+ return null;
6523
+ const optional = lowerer.runtimeOptionalIdentifierValue(expr);
6524
+ if (optional === null)
6525
+ return null;
6526
+ const checked = lowerer.mapTypeOf(lowerer.typeOf(expr));
6527
+ if (checked === null ||
6528
+ (checked.kind === "union" && lowerer.armTag(checked.unionId, UNDEFINED_T) >= 0))
6529
+ return null;
6530
+ return optional.value;
6531
+ }
6532
+ /** A presence-test operand: an absence-aware element or field read, an
6533
+ * identifier's runtime-optional storage, or the ordinary lowering. */
6534
+ export function lowerPresenceOperand(lowerer, node) {
6535
+ // An unassigned deferred-init field observes its undefined slot too.
6536
+ return deferredSlotOr(lowerer, lowerAbsenceProbe(lowerer, node) ??
6537
+ runtimeOptionalStorageOperand(lowerer, node) ??
6538
+ lowerer.lowerExpr(node));
6539
+ }
6333
6540
  /** A keyed read used only to observe absence (`if (map[k])`, or the left
6334
6541
  * side of `||`/`??`). JavaScript answers undefined for missing record keys
6335
6542
  * and array indices even when noUncheckedIndexedAccess is disabled. Keep
@@ -6542,13 +6749,7 @@ export function lowerElementCompound(lowerer, expr, op) {
6542
6749
  ? lowerer.narrowedArmHelper(receiver.type.unionId, present, locOf(target.expression))
6543
6750
  : null;
6544
6751
  if (helper)
6545
- receiver = {
6546
- kind: "call",
6547
- callee: helper,
6548
- args: [receiver],
6549
- type: present,
6550
- loc: locOf(target.expression),
6551
- };
6752
+ receiver = lowerer.checkedNarrowCall(helper, receiver, present, locOf(target.expression));
6552
6753
  }
6553
6754
  if (receiver.type.kind !== receiverType.kind) {
6554
6755
  lowerer.unsupported("SC1090", target.expression, "compound assignment through a non-native array or byte view");
@@ -6563,12 +6764,15 @@ export function lowerElementCompound(lowerer, expr, op) {
6563
6764
  const oldValue = receiver.type.kind === "array"
6564
6765
  ? arrayValueRead(lowerer, receiverRef(), indexRef(), receiver.type.elem, locOf(target))
6565
6766
  : {
6767
+ // An invalid index reads undefined in Node, which every numeric
6768
+ // compound operator turns into NaN; the write is then ignored.
6566
6769
  kind: "bytesIntrinsic",
6567
6770
  method: "get",
6568
6771
  receiver: receiverRef(),
6569
6772
  args: [indexRef()],
6570
6773
  type: F64,
6571
6774
  loc: locOf(target),
6775
+ invalidNaN: true,
6572
6776
  };
6573
6777
  const oldLocal = lowerer.declareHiddenLocal("%compoundOld", oldValue.type);
6574
6778
  const oldRef = () => varRef(oldLocal.id, oldValue.type, loc);
@@ -7184,13 +7388,7 @@ export function lowerElementWrite(lowerer, expr) {
7184
7388
  ? lowerer.narrowedArmHelper(arr.type.unionId, present, locOf(target.expression))
7185
7389
  : null;
7186
7390
  if (helper) {
7187
- arr = {
7188
- kind: "call",
7189
- callee: helper,
7190
- args: [arr],
7191
- type: present,
7192
- loc: locOf(target.expression),
7193
- };
7391
+ arr = lowerer.checkedNarrowCall(helper, arr, present, locOf(target.expression));
7194
7392
  }
7195
7393
  }
7196
7394
  if (arr.type.kind !== "array") {
@@ -7308,7 +7506,7 @@ export function ensureString(lowerer, e, node) {
7308
7506
  narrowed.kind === "bigint")) {
7309
7507
  const helper = lowerer.narrowedArmHelper(e.type.unionId, narrowed, e.loc);
7310
7508
  if (helper) {
7311
- return ensureString(lowerer, { kind: "call", callee: helper, args: [e], type: narrowed, loc: e.loc }, node);
7509
+ return ensureString(lowerer, lowerer.checkedNarrowCall(helper, e, narrowed, e.loc), node);
7312
7510
  }
7313
7511
  }
7314
7512
  if (narrowed?.kind === "union" &&
@@ -7581,10 +7779,20 @@ export function lowerAsExpression(lowerer, expr) {
7581
7779
  if (target && target.kind !== "union" && !typeEquals(target, inner.type)) {
7582
7780
  const helper = lowerer.narrowedArmHelper(inner.type.unionId, target, locOf(expr));
7583
7781
  if (helper) {
7584
- return { kind: "call", callee: helper, args: [inner], type: target, loc: locOf(expr) };
7782
+ return lowerer.checkedNarrowCall(helper, inner, target, locOf(expr));
7585
7783
  }
7586
7784
  }
7587
7785
  }
7786
+ // `node.parent as Sub | undefined`: a union target whose class arm is
7787
+ // narrower than the stored class gets the same checked class view as
7788
+ // `node.parent as Sub`; the other arms keep their identical tags.
7789
+ if (target?.kind === "union" &&
7790
+ (inner.type.kind === "union" || inner.type.kind === "object") &&
7791
+ !typeEquals(target, inner.type)) {
7792
+ const asserted = checkedClassUnionAssertion(lowerer, inner, target, locOf(expr));
7793
+ if (asserted)
7794
+ return asserted;
7795
+ }
7588
7796
  return inner; // erasure, unchanged
7589
7797
  }
7590
7798
  if (inner.type.kind === "jsval") {
@@ -7711,7 +7919,7 @@ export function lowerPrefixUnary(lowerer, expr) {
7711
7919
  }
7712
7920
  case ts.SyntaxKind.ExclamationToken: {
7713
7921
  // `!x` is ToBoolean-then-negate: f64/string operands go through toBool.
7714
- const operand = lowerer.ensureBool(lowerer.lowerExpr(expr.operand), expr.operand);
7922
+ const operand = lowerer.ensureBool(deferredSlotOr(lowerer, runtimeOptionalStorageOperand(lowerer, expr.operand) ?? lowerer.lowerExpr(expr.operand)), expr.operand);
7715
7923
  return { kind: "unary", op: "!", operand, type: BOOL, loc };
7716
7924
  }
7717
7925
  case ts.SyntaxKind.TildeToken: {
@@ -7816,7 +8024,15 @@ export function lowerIncDec(lowerer, expr, prefix) {
7816
8024
  const type = raw.type;
7817
8025
  const read = type.kind === "array"
7818
8026
  ? arrayValueRead(lowerer, receiver, index, type.elem, loc)
7819
- : { kind: "bytesIntrinsic", method: "get", receiver, args: [index], type: F64, loc };
8027
+ : {
8028
+ kind: "bytesIntrinsic",
8029
+ method: "get",
8030
+ receiver,
8031
+ args: [index],
8032
+ type: F64,
8033
+ loc,
8034
+ invalidNaN: true,
8035
+ };
7820
8036
  return finish(read, (value) => type.kind === "array"
7821
8037
  ? arrayValueStore(lowerer, receiver, index, lowerer.coerceInto(access, value, type.elem), type.elem, loc)
7822
8038
  : {
@@ -7848,6 +8064,7 @@ export function lowerIncDec(lowerer, expr, prefix) {
7848
8064
  ? lowerer.fieldTarget(access)
7849
8065
  : symbolFieldTarget(lowerer, access);
7850
8066
  if (target && lowerer.dynConvertible(target.fieldType)) {
8067
+ checkDeferredMemberReceiver(lowerer, target, access);
7851
8068
  target.obj = save(target.obj, "%incrementReceiver");
7852
8069
  return finish(lowerer.fieldGetExpr(target, loc, access), (value) => lowerer.fieldSetStmt(target, lowerer.coerceInto(access, value, target.fieldType), loc, access));
7853
8070
  }
@@ -8362,7 +8579,7 @@ export function lowerBinary(lowerer, expr) {
8362
8579
  const nullTest = lowerLooseNullCompare(lowerer, expr, loc);
8363
8580
  if (nullTest)
8364
8581
  return nullTest;
8365
- const loose = lowerAbstractEquality(lowerer, lowerer.lowerExpr(expr.left), lowerer.lowerExpr(expr.right), op === ts.SyntaxKind.ExclamationEqualsToken, loc);
8582
+ const loose = lowerAbstractEquality(lowerer, deferredSlotOr(lowerer, lowerer.lowerExpr(expr.left)), deferredSlotOr(lowerer, lowerer.lowerExpr(expr.right)), op === ts.SyntaxKind.ExclamationEqualsToken, loc);
8366
8583
  if (loose)
8367
8584
  return loose;
8368
8585
  lowerer.unsupported("SC1040", expr, undefined, "object-to-primitive loose equality can call user-defined valueOf/toString methods — compare explicit primitive conversions instead");
@@ -8409,12 +8626,26 @@ export function lowerBinary(lowerer, expr) {
8409
8626
  }
8410
8627
  const strictEquality = op === ts.SyntaxKind.EqualsEqualsEqualsToken ||
8411
8628
  op === ts.SyntaxKind.ExclamationEqualsEqualsToken;
8629
+ // An identifier whose storage is runtime-optional is compared by its
8630
+ // stored value: the checker's narrowing to the present arm is not a
8631
+ // runtime proof. Identifier reads are pure, so taking the stored value
8632
+ // after both operands lowered keeps the evaluation order. A union on
8633
+ // the other side keeps the narrowed read (union-to-union comparison
8634
+ // has no lowering).
8412
8635
  let left = strictEquality
8413
8636
  ? (lowerAbsenceProbe(lowerer, expr.left) ?? lowerer.lowerExpr(expr.left))
8414
8637
  : lowerer.lowerExpr(expr.left);
8415
8638
  let right = strictEquality
8416
8639
  ? (lowerAbsenceProbe(lowerer, expr.right) ?? lowerer.lowerExpr(expr.right))
8417
8640
  : lowerer.lowerExpr(expr.right);
8641
+ if (strictEquality) {
8642
+ const storedLeft = runtimeOptionalStorageOperand(lowerer, expr.left);
8643
+ const storedRight = runtimeOptionalStorageOperand(lowerer, expr.right);
8644
+ if (storedLeft !== null && right.type.kind !== "union")
8645
+ left = storedLeft;
8646
+ if (storedRight !== null && left.type.kind !== "union")
8647
+ right = storedRight;
8648
+ }
8418
8649
  if (strictEquality && (left.type.kind === "caught" || right.type.kind === "caught")) {
8419
8650
  if (left.type.kind === "caught")
8420
8651
  left = { kind: "caughtToDyn", value: left, type: DYN, loc: left.loc };
@@ -9266,7 +9497,9 @@ function lowerLogicalChain(lowerer, expr) {
9266
9497
  current = left;
9267
9498
  continue;
9268
9499
  }
9269
- result = lowerLogicalPair(lowerer, current, lowerAbsenceProbe(lowerer, left) ?? lowerer.lowerExpr(left));
9500
+ result = lowerLogicalPair(lowerer, current, current.operatorToken.kind === ts.SyntaxKind.BarBarToken
9501
+ ? lowerPresenceOperand(lowerer, left)
9502
+ : (lowerAbsenceProbe(lowerer, left) ?? lowerer.lowerExpr(left)));
9270
9503
  break;
9271
9504
  }
9272
9505
  for (let i = parents.length - 1; i >= 0; i--) {
@@ -9921,11 +10154,12 @@ function lowerUnionTypeofTest(lowerer, expr, loc) {
9921
10154
  for (const [a, b] of operandPairs(expr)) {
9922
10155
  if (!ts.isTypeOfExpression(a))
9923
10156
  continue;
9924
- if (lowerer.mapTypeOf(lowerer.typeOf(a.expression))?.kind !== "union")
10157
+ const stored = runtimeOptionalStorageOperand(lowerer, a.expression);
10158
+ if (stored === null && lowerer.mapTypeOf(lowerer.typeOf(a.expression))?.kind !== "union")
9925
10159
  continue;
9926
10160
  if (!ts.isStringLiteral(b))
9927
10161
  continue; // bare-typeof + strEq handles pure operands
9928
- const value = lowerer.lowerExpr(a.expression);
10162
+ const value = stored ?? lowerer.lowerExpr(a.expression);
9929
10163
  if (value.type.kind !== "union")
9930
10164
  continue; // defensive: an already-narrowed use
9931
10165
  const unionId = value.type.unionId;
@@ -12088,13 +12322,7 @@ export function lowerUnionProperty(lowerer, expr) {
12088
12322
  if (receiver === null) {
12089
12323
  const helper = lowerer.narrowedArmHelper(value.type.unionId, objectType, locOf(expr.expression));
12090
12324
  if (helper !== null)
12091
- receiver = {
12092
- kind: "call",
12093
- callee: helper,
12094
- args: [value],
12095
- type: objectType,
12096
- loc: locOf(expr.expression),
12097
- };
12325
+ receiver = lowerer.checkedNarrowCall(helper, value, objectType, locOf(expr.expression));
12098
12326
  }
12099
12327
  if (receiver !== null) {
12100
12328
  return {
@@ -12306,13 +12534,7 @@ function classFieldTarget(lowerer, receiverNode, receiverType, fieldName, saved)
12306
12534
  if (obj.type.kind === "union") {
12307
12535
  const helper = lowerer.narrowedArmHelper(obj.type.unionId, receiverType, locOf(receiverNode));
12308
12536
  obj = helper
12309
- ? {
12310
- kind: "call",
12311
- callee: helper,
12312
- args: [obj],
12313
- type: receiverType,
12314
- loc: locOf(receiverNode),
12315
- }
12537
+ ? lowerer.checkedNarrowCall(helper, obj, receiverType, locOf(receiverNode))
12316
12538
  : lowerer.maybeNarrow(obj, receiverNode);
12317
12539
  }
12318
12540
  return lowerer.coerceInto(receiverNode, obj, receiverType);
@@ -12476,13 +12698,7 @@ export function fieldTarget(lowerer, access) {
12476
12698
  ? lowerer.narrowedArmHelper(obj.type.unionId, present, locOf(access.expression))
12477
12699
  : null;
12478
12700
  obj = helper
12479
- ? {
12480
- kind: "call",
12481
- callee: helper,
12482
- args: [obj],
12483
- type: present,
12484
- loc: locOf(access.expression),
12485
- }
12701
+ ? lowerer.checkedNarrowCall(helper, obj, present, locOf(access.expression))
12486
12702
  : lowerer.maybeNarrow(obj, access.expression);
12487
12703
  }
12488
12704
  if (obj.type.kind !== "record")
@@ -12689,6 +12905,16 @@ function symbolFieldTarget(lowerer, expr) {
12689
12905
  * tsc-clean (the property types as the setter's param), but Node yields
12690
12906
  * undefined, which these property types cannot represent. */
12691
12907
  export function fieldGetExpr(lowerer, target, loc, blame) {
12908
+ // A member read through an unassigned deferred-init field throws Node's
12909
+ // member-read TypeError instead of the generic checked extraction.
12910
+ if (target.container === "class" &&
12911
+ ts.isPropertyAccessExpression(blame) &&
12912
+ target.obj.type.kind === "object" &&
12913
+ lowerer.deferredFieldSlot(target.obj) !== null) {
12914
+ const checked = lowerer.runtimeOptionalPropertyReceiver(blame.expression, target.obj, target.obj.type, target.field);
12915
+ if (checked)
12916
+ target = { ...target, obj: checked };
12917
+ }
12692
12918
  if (target.container === "dynamic")
12693
12919
  return lowerer.coerceInto(blame, {
12694
12920
  kind: "dynKeyGet",
@@ -12812,6 +13038,34 @@ export function fieldGetExpr(lowerer, target, loc, blame) {
12812
13038
  if (lowerer.classes.get(target.className)?.deferredInitFields?.has(target.field) === true &&
12813
13039
  target.fieldType.kind === "union") {
12814
13040
  const inner = lowerer.stripUndefinedArm(target.fieldType);
13041
+ // Reference arms over a stable receiver check inline: the present
13042
+ // arm is a plain projection of the slot, so ordinary reads keep their
13043
+ // borrowed form and only an unassigned slot reaches the throw.
13044
+ const unionId = target.fieldType.unionId;
13045
+ const presentTag = lowerer.armTag(unionId, inner);
13046
+ const undefTag = lowerer.armTag(unionId, UNDEFINED_T);
13047
+ if (inner.kind === "object" &&
13048
+ presentTag >= 0 &&
13049
+ undefTag >= 0 &&
13050
+ lowerer.unions.get(unionId)?.arms.length === 2 &&
13051
+ isSafeToRepeat(read)) {
13052
+ return {
13053
+ kind: "ternary",
13054
+ cond: {
13055
+ kind: "unionIsTag",
13056
+ unionId,
13057
+ tag: undefTag,
13058
+ negated: false,
13059
+ value: read,
13060
+ type: BOOL,
13061
+ loc,
13062
+ },
13063
+ then: nodeThrowExpr(1, "", DEFERRED_READ_MESSAGE, inner, loc),
13064
+ else_: { kind: "unionNarrow", unionId, tag: presentTag, value: read, type: inner, loc },
13065
+ type: inner,
13066
+ loc,
13067
+ };
13068
+ }
12815
13069
  const helper = lowerer.deferredReadHelper(target.fieldType.unionId, inner, loc);
12816
13070
  if (helper)
12817
13071
  return { kind: "call", callee: helper, args: [read], type: inner, loc };
@@ -12831,6 +13085,75 @@ export function fieldGetExpr(lowerer, target, loc, blame) {
12831
13085
  * call). A write to a getter-only property never gets here in a clean
12832
13086
  * program (tsc's TS2540 is the fence); the rejection is the backstop. */
12833
13087
  export function fieldSetStmt(lowerer, target, value, loc, blame) {
13088
+ // A member write through an unassigned deferred-init field: the value
13089
+ // still evaluates first, then the write throws Node's TypeError.
13090
+ const deferredSlot = target.container === "class" &&
13091
+ !((target.field === "message" || target.field === "name") &&
13092
+ (target.className === "%Error" || lowerer.isSubclassOf(target.className, "%Error")))
13093
+ ? lowerer.deferredFieldSlot(target.obj)
13094
+ : null;
13095
+ if (target.container === "class" && deferredSlot?.type.kind === "union") {
13096
+ const unionId = deferredSlot.type.unionId;
13097
+ const undefTag = lowerer.armTag(unionId, UNDEFINED_T);
13098
+ const presentTag = lowerer.armTag(unionId, target.obj.type);
13099
+ if (undefTag >= 0 && presentTag >= 0) {
13100
+ // A value that cannot write anything leaves the field unchanged, so
13101
+ // the field is read after it (no snapshot of the slot).
13102
+ const late = isSafeToRepeat(deferredSlot) && writeFree(value);
13103
+ const receiver = late
13104
+ ? null
13105
+ : lowerer.declareHiddenLocal("%deferredWriteObject", deferredSlot.type);
13106
+ const stored = lowerer.declareHiddenLocal("%deferredWriteValue", value.type);
13107
+ const receiverRef = receiver ? varRef(receiver.id, receiver.type, loc) : deferredSlot;
13108
+ const result = varRef(stored.id, stored.type, loc);
13109
+ const write = {
13110
+ kind: "fieldSet",
13111
+ obj: {
13112
+ kind: "unionNarrow",
13113
+ unionId,
13114
+ tag: presentTag,
13115
+ value: receiverRef,
13116
+ type: target.obj.type,
13117
+ loc,
13118
+ },
13119
+ className: target.className,
13120
+ field: target.field,
13121
+ value: result,
13122
+ loc,
13123
+ };
13124
+ return {
13125
+ kind: "exprStmt",
13126
+ expr: {
13127
+ kind: "seqExpr",
13128
+ stmts: [
13129
+ ...(receiver
13130
+ ? [{ kind: "varDecl", localId: receiver.id, init: deferredSlot, loc }]
13131
+ : []),
13132
+ { kind: "varDecl", localId: stored.id, init: value, loc },
13133
+ ],
13134
+ result: {
13135
+ kind: "ternary",
13136
+ cond: {
13137
+ kind: "unionIsTag",
13138
+ unionId,
13139
+ tag: undefTag,
13140
+ value: receiverRef,
13141
+ negated: false,
13142
+ type: BOOL,
13143
+ loc,
13144
+ },
13145
+ then: nodeThrowExpr(1, "", `Cannot set properties of undefined (setting '${target.field}')`, result.type, loc),
13146
+ else_: { kind: "seqExpr", stmts: [write], result, type: result.type, loc },
13147
+ type: result.type,
13148
+ loc,
13149
+ },
13150
+ type: result.type,
13151
+ loc,
13152
+ },
13153
+ loc,
13154
+ };
13155
+ }
13156
+ }
12834
13157
  if (target.container === "dynamic")
12835
13158
  return {
12836
13159
  kind: "exprStmt",
@@ -13148,6 +13471,7 @@ function lowerFieldCompoundValue(lowerer, access, op, rhsNode, loc) {
13148
13471
  const target = targetOf();
13149
13472
  if (!target)
13150
13473
  lowerer.unsupported("SC1090", access, "compound assignment to unsupported field targets");
13474
+ checkDeferredMemberReceiver(lowerer, target, access);
13151
13475
  target.obj = save(target.obj, "%compoundReceiver");
13152
13476
  // Accessors observe getter, RHS side effects, then setter, all through
13153
13477
  // the saved receiver.