@scriptc/compiler 0.2.7 → 0.2.9

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 (474) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +3 -0
  2. package/dist/backend/cycle-analysis.js +50 -17
  3. package/dist/backend/cycle-analysis.js.map +1 -1
  4. package/dist/backend/cycle-analysis.test.js +138 -14
  5. package/dist/backend/cycle-analysis.test.js.map +1 -1
  6. package/dist/backend/cycle-mutability.d.ts +31 -6
  7. package/dist/backend/cycle-mutability.js +120 -18
  8. package/dist/backend/cycle-mutability.js.map +1 -1
  9. package/dist/backend/llvm/alloc.d.ts +16 -3
  10. package/dist/backend/llvm/alloc.js +78 -23
  11. package/dist/backend/llvm/alloc.js.map +1 -1
  12. package/dist/backend/llvm/alloc.test.js +5 -5
  13. package/dist/backend/llvm/alloc.test.js.map +1 -1
  14. package/dist/backend/llvm/blocks.d.ts +9 -0
  15. package/dist/backend/llvm/blocks.js +9 -0
  16. package/dist/backend/llvm/blocks.js.map +1 -1
  17. package/dist/backend/llvm/borrowed-receivers.d.ts +7 -0
  18. package/dist/backend/llvm/borrowed-receivers.js +39 -0
  19. package/dist/backend/llvm/borrowed-receivers.js.map +1 -1
  20. package/dist/backend/llvm/byte-numbers.js +2 -3
  21. package/dist/backend/llvm/byte-numbers.js.map +1 -1
  22. package/dist/backend/llvm/call-lifetimes.d.ts +4 -1
  23. package/dist/backend/llvm/call-lifetimes.js +14 -3
  24. package/dist/backend/llvm/call-lifetimes.js.map +1 -1
  25. package/dist/backend/llvm/call-lifetimes.test.js +8 -3
  26. package/dist/backend/llvm/call-lifetimes.test.js.map +1 -1
  27. package/dist/backend/llvm/checked-narrows.d.ts +24 -0
  28. package/dist/backend/llvm/checked-narrows.js +108 -0
  29. package/dist/backend/llvm/checked-narrows.js.map +1 -0
  30. package/dist/backend/llvm/checked-narrows.test.d.ts +1 -0
  31. package/dist/backend/llvm/checked-narrows.test.js +208 -0
  32. package/dist/backend/llvm/checked-narrows.test.js.map +1 -0
  33. package/dist/backend/llvm/classes.d.ts +13 -1
  34. package/dist/backend/llvm/classes.js +32 -23
  35. package/dist/backend/llvm/classes.js.map +1 -1
  36. package/dist/backend/llvm/classes.test.js +32 -3
  37. package/dist/backend/llvm/classes.test.js.map +1 -1
  38. package/dist/backend/llvm/common.d.ts +17 -0
  39. package/dist/backend/llvm/common.js +28 -0
  40. package/dist/backend/llvm/common.js.map +1 -1
  41. package/dist/backend/llvm/debug-info.d.ts +6 -2
  42. package/dist/backend/llvm/debug-info.js +11 -1
  43. package/dist/backend/llvm/debug-info.js.map +1 -1
  44. package/dist/backend/llvm/dense-array-access.js +1 -1
  45. package/dist/backend/llvm/dense-array-access.test.js +89 -0
  46. package/dist/backend/llvm/dense-array-access.test.js.map +1 -1
  47. package/dist/backend/llvm/dyn.d.ts +8 -4
  48. package/dist/backend/llvm/dyn.js +58 -31
  49. package/dist/backend/llvm/dyn.js.map +1 -1
  50. package/dist/backend/llvm/emitter.d.ts +227 -12
  51. package/dist/backend/llvm/emitter.js +1492 -169
  52. package/dist/backend/llvm/emitter.js.map +1 -1
  53. package/dist/backend/llvm/emitter.test.js +54 -1
  54. package/dist/backend/llvm/emitter.test.js.map +1 -1
  55. package/dist/backend/llvm/expr-async.js +4 -4
  56. package/dist/backend/llvm/expr-async.js.map +1 -1
  57. package/dist/backend/llvm/expr-bytes.d.ts +1 -1
  58. package/dist/backend/llvm/expr-bytes.js +116 -32
  59. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  60. package/dist/backend/llvm/expr-callbacks.js +29 -21
  61. package/dist/backend/llvm/expr-callbacks.js.map +1 -1
  62. package/dist/backend/llvm/expr-calls.d.ts +5 -0
  63. package/dist/backend/llvm/expr-calls.js +55 -10
  64. package/dist/backend/llvm/expr-calls.js.map +1 -1
  65. package/dist/backend/llvm/expr-containers.d.ts +7 -1
  66. package/dist/backend/llvm/expr-containers.js +231 -28
  67. package/dist/backend/llvm/expr-containers.js.map +1 -1
  68. package/dist/backend/llvm/expr-context.d.ts +2 -0
  69. package/dist/backend/llvm/expr-control.js +70 -14
  70. package/dist/backend/llvm/expr-control.js.map +1 -1
  71. package/dist/backend/llvm/expr-dynamic.js +75 -21
  72. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  73. package/dist/backend/llvm/expr-island.js +3 -8
  74. package/dist/backend/llvm/expr-island.js.map +1 -1
  75. package/dist/backend/llvm/expr-primitives.js +41 -12
  76. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  77. package/dist/backend/llvm/expr-primitives.test.js +50 -2
  78. package/dist/backend/llvm/expr-primitives.test.js.map +1 -1
  79. package/dist/backend/llvm/expr-records.js +28 -14
  80. package/dist/backend/llvm/expr-records.js.map +1 -1
  81. package/dist/backend/llvm/expr-stream-bridges.d.ts +3 -0
  82. package/dist/backend/llvm/expr-stream-bridges.js +114 -42
  83. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  84. package/dist/backend/llvm/expr-stream-callbacks.js +6 -3
  85. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
  86. package/dist/backend/llvm/layouts.d.ts +2 -1
  87. package/dist/backend/llvm/layouts.js +2 -2
  88. package/dist/backend/llvm/layouts.js.map +1 -1
  89. package/dist/backend/llvm/lib-abi.js +10 -0
  90. package/dist/backend/llvm/lib-abi.js.map +1 -1
  91. package/dist/backend/llvm/lib-filesystem.js +25 -13
  92. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  93. package/dist/backend/llvm/lib-process.js +8 -8
  94. package/dist/backend/llvm/lib-process.js.map +1 -1
  95. package/dist/backend/llvm/lib-shared.js +2 -0
  96. package/dist/backend/llvm/lib-shared.js.map +1 -1
  97. package/dist/backend/llvm/local-array-reads.d.ts +17 -6
  98. package/dist/backend/llvm/local-array-reads.js +223 -51
  99. package/dist/backend/llvm/local-array-reads.js.map +1 -1
  100. package/dist/backend/llvm/local-array-reads.test.js +7 -3
  101. package/dist/backend/llvm/local-array-reads.test.js.map +1 -1
  102. package/dist/backend/llvm/local-union-storage.js +10 -6
  103. package/dist/backend/llvm/local-union-storage.js.map +1 -1
  104. package/dist/backend/llvm/local-union-storage.test.js +3 -2
  105. package/dist/backend/llvm/local-union-storage.test.js.map +1 -1
  106. package/dist/backend/llvm/map-number-lookup.d.ts +18 -0
  107. package/dist/backend/llvm/map-number-lookup.js +62 -0
  108. package/dist/backend/llvm/map-number-lookup.js.map +1 -0
  109. package/dist/backend/llvm/map-read-lifetimes.d.ts +6 -0
  110. package/dist/backend/llvm/map-read-lifetimes.js +24 -3
  111. package/dist/backend/llvm/map-read-lifetimes.js.map +1 -1
  112. package/dist/backend/llvm/map-read-lifetimes.test.js +38 -19
  113. package/dist/backend/llvm/map-read-lifetimes.test.js.map +1 -1
  114. package/dist/backend/llvm/nullable-unions.d.ts +68 -0
  115. package/dist/backend/llvm/nullable-unions.js +132 -0
  116. package/dist/backend/llvm/nullable-unions.js.map +1 -0
  117. package/dist/backend/llvm/publish.d.ts +58 -0
  118. package/dist/backend/llvm/publish.js +286 -0
  119. package/dist/backend/llvm/publish.js.map +1 -0
  120. package/dist/backend/llvm/rebound-parameters.d.ts +12 -0
  121. package/dist/backend/llvm/rebound-parameters.js +72 -0
  122. package/dist/backend/llvm/rebound-parameters.js.map +1 -0
  123. package/dist/backend/llvm/rebound-parameters.test.d.ts +1 -0
  124. package/dist/backend/llvm/rebound-parameters.test.js +67 -0
  125. package/dist/backend/llvm/rebound-parameters.test.js.map +1 -0
  126. package/dist/backend/llvm/reference-effects.d.ts +18 -2
  127. package/dist/backend/llvm/reference-effects.js +140 -17
  128. package/dist/backend/llvm/reference-effects.js.map +1 -1
  129. package/dist/backend/llvm/reference-effects.test.js +52 -1
  130. package/dist/backend/llvm/reference-effects.test.js.map +1 -1
  131. package/dist/backend/llvm/shapes.d.ts +58 -19
  132. package/dist/backend/llvm/shapes.js +171 -62
  133. package/dist/backend/llvm/shapes.js.map +1 -1
  134. package/dist/backend/llvm/shapes.test.js +36 -11
  135. package/dist/backend/llvm/shapes.test.js.map +1 -1
  136. package/dist/backend/llvm/stack-unions.test.js +5 -2
  137. package/dist/backend/llvm/stack-unions.test.js.map +1 -1
  138. package/dist/backend/llvm/string-construction.d.ts +10 -0
  139. package/dist/backend/llvm/string-construction.js +42 -0
  140. package/dist/backend/llvm/string-construction.js.map +1 -1
  141. package/dist/backend/llvm/string-key-hash.d.ts +9 -2
  142. package/dist/backend/llvm/string-key-hash.js +20 -3
  143. package/dist/backend/llvm/string-key-hash.js.map +1 -1
  144. package/dist/backend/llvm/string-key-hash.test.js +14 -3
  145. package/dist/backend/llvm/string-key-hash.test.js.map +1 -1
  146. package/dist/backend/llvm/string-lifetimes.test.js +24 -11
  147. package/dist/backend/llvm/string-lifetimes.test.js.map +1 -1
  148. package/dist/backend/llvm/string-reads.d.ts +7 -0
  149. package/dist/backend/llvm/string-reads.js +79 -0
  150. package/dist/backend/llvm/string-reads.js.map +1 -0
  151. package/dist/backend/llvm/string-slices.js +1 -1
  152. package/dist/backend/llvm/switch-dispatch.test.js +1 -1
  153. package/dist/backend/llvm/switch-dispatch.test.js.map +1 -1
  154. package/dist/backend/llvm/test-boxed-unions.d.ts +5 -0
  155. package/dist/backend/llvm/test-boxed-unions.js +13 -0
  156. package/dist/backend/llvm/test-boxed-unions.js.map +1 -0
  157. package/dist/backend/llvm/trunc.d.ts +8 -0
  158. package/dist/backend/llvm/trunc.js +28 -0
  159. package/dist/backend/llvm/trunc.js.map +1 -0
  160. package/dist/backend/llvm/union-repr.d.ts +15 -0
  161. package/dist/backend/llvm/union-repr.js +89 -0
  162. package/dist/backend/llvm/union-repr.js.map +1 -0
  163. package/dist/backend/llvm/virtual-borrows.d.ts +31 -0
  164. package/dist/backend/llvm/virtual-borrows.js +82 -0
  165. package/dist/backend/llvm/virtual-borrows.js.map +1 -0
  166. package/dist/backend/llvm/walk-borrows.d.ts +43 -0
  167. package/dist/backend/llvm/walk-borrows.js +150 -0
  168. package/dist/backend/llvm/walk-borrows.js.map +1 -0
  169. package/dist/backend/llvm/walk-borrows.test.d.ts +1 -0
  170. package/dist/backend/llvm/walk-borrows.test.js +119 -0
  171. package/dist/backend/llvm/walk-borrows.test.js.map +1 -0
  172. package/dist/backend/llvm/walkers.d.ts +5 -1
  173. package/dist/backend/llvm/walkers.js +24 -21
  174. package/dist/backend/llvm/walkers.js.map +1 -1
  175. package/dist/backend/loop-polls.d.ts +14 -0
  176. package/dist/backend/loop-polls.js +100 -0
  177. package/dist/backend/loop-polls.js.map +1 -0
  178. package/dist/backend/loop-polls.test.d.ts +1 -0
  179. package/dist/backend/loop-polls.test.js +86 -0
  180. package/dist/backend/loop-polls.test.js.map +1 -0
  181. package/dist/backend/may-throw.d.ts +29 -1
  182. package/dist/backend/may-throw.js +365 -3
  183. package/dist/backend/may-throw.js.map +1 -1
  184. package/dist/backend/may-throw.test.js +136 -1
  185. package/dist/backend/may-throw.test.js.map +1 -1
  186. package/dist/backend/native/runtime-inputs.d.ts +1 -1
  187. package/dist/backend/native/runtime-inputs.js +1 -0
  188. package/dist/backend/native/runtime-inputs.js.map +1 -1
  189. package/dist/backend/native-codegen-core.d.ts +7 -5
  190. package/dist/backend/native-codegen-core.js +14 -9
  191. package/dist/backend/native-codegen-core.js.map +1 -1
  192. package/dist/backend/native-codegen.d.ts +2 -0
  193. package/dist/backend/native-codegen.js +21 -2
  194. package/dist/backend/native-codegen.js.map +1 -1
  195. package/dist/backend/native-codegen.test.js +41 -10
  196. package/dist/backend/native-codegen.test.js.map +1 -1
  197. package/dist/backend/native-tools.d.ts +2 -0
  198. package/dist/backend/native-tools.js +3 -0
  199. package/dist/backend/native-tools.js.map +1 -1
  200. package/dist/backend/publication.d.ts +28 -0
  201. package/dist/backend/publication.js +155 -0
  202. package/dist/backend/publication.js.map +1 -0
  203. package/dist/backend/publication.test.d.ts +1 -0
  204. package/dist/backend/publication.test.js +72 -0
  205. package/dist/backend/publication.test.js.map +1 -0
  206. package/dist/backend/runtime-abi.d.ts +2 -2
  207. package/dist/backend/runtime-abi.js +2 -2
  208. package/dist/backend/runtime-abi.js.map +1 -1
  209. package/dist/backend/runtime-pack-targets.test.js +1 -1
  210. package/dist/backend/runtime-pack-targets.test.js.map +1 -1
  211. package/dist/backend/runtime-pack.test.js +1 -1
  212. package/dist/backend/runtime-pack.test.js.map +1 -1
  213. package/dist/cli/command.js +78 -8
  214. package/dist/cli/command.js.map +1 -1
  215. package/dist/cli/output-options.d.ts +1 -0
  216. package/dist/cli/output-options.js +3 -0
  217. package/dist/cli/output-options.js.map +1 -1
  218. package/dist/cli/usage.d.ts +8 -1
  219. package/dist/cli/usage.js +14 -1
  220. package/dist/cli/usage.js.map +1 -1
  221. package/dist/compile-types.d.ts +17 -3
  222. package/dist/coverage/report.d.ts +25 -2
  223. package/dist/coverage/report.js +161 -33
  224. package/dist/coverage/report.js.map +1 -1
  225. package/dist/coverage/verdict-cache.d.ts +63 -0
  226. package/dist/coverage/verdict-cache.js +193 -0
  227. package/dist/coverage/verdict-cache.js.map +1 -0
  228. package/dist/coverage/verdict-cache.test.d.ts +1 -0
  229. package/dist/coverage/verdict-cache.test.js +52 -0
  230. package/dist/coverage/verdict-cache.test.js.map +1 -0
  231. package/dist/coverage/verdict-semantic.d.ts +2 -0
  232. package/dist/coverage/verdict-semantic.js +24 -0
  233. package/dist/coverage/verdict-semantic.js.map +1 -0
  234. package/dist/coverage/verdict-startup.d.ts +15 -0
  235. package/dist/coverage/verdict-startup.js +66 -0
  236. package/dist/coverage/verdict-startup.js.map +1 -0
  237. package/dist/diagnostics/diagnostic.d.ts +29 -1
  238. package/dist/diagnostics/diagnostic.js +74 -4
  239. package/dist/diagnostics/diagnostic.js.map +1 -1
  240. package/dist/diagnostics/envelope.d.ts +130 -0
  241. package/dist/diagnostics/envelope.js +257 -0
  242. package/dist/diagnostics/envelope.js.map +1 -0
  243. package/dist/diagnostics/envelope.test.d.ts +1 -0
  244. package/dist/diagnostics/envelope.test.js +91 -0
  245. package/dist/diagnostics/envelope.test.js.map +1 -0
  246. package/dist/diagnostics/render.d.ts +3 -0
  247. package/dist/diagnostics/render.js +13 -2
  248. package/dist/diagnostics/render.js.map +1 -1
  249. package/dist/executable/executable-cache.d.ts +2 -0
  250. package/dist/executable/executable-cache.js +3 -0
  251. package/dist/executable/executable-cache.js.map +1 -1
  252. package/dist/executable/executable-cache.test.js +1 -0
  253. package/dist/executable/executable-cache.test.js.map +1 -1
  254. package/dist/executable/prepare.d.ts +4 -0
  255. package/dist/executable/prepare.js +7 -1
  256. package/dist/executable/prepare.js.map +1 -1
  257. package/dist/frontend/analysis.js +1 -0
  258. package/dist/frontend/analysis.js.map +1 -1
  259. package/dist/frontend/lowering/array-values.d.ts +7 -0
  260. package/dist/frontend/lowering/array-values.js +157 -5
  261. package/dist/frontend/lowering/array-values.js.map +1 -1
  262. package/dist/frontend/lowering/builtins/numbers.js +29 -1
  263. package/dist/frontend/lowering/builtins/numbers.js.map +1 -1
  264. package/dist/frontend/lowering/builtins/process.d.ts +4 -0
  265. package/dist/frontend/lowering/builtins/process.js +10 -0
  266. package/dist/frontend/lowering/builtins/process.js.map +1 -1
  267. package/dist/frontend/lowering/builtins/strings.js +4 -1
  268. package/dist/frontend/lowering/builtins/strings.js.map +1 -1
  269. package/dist/frontend/lowering/builtins/workers.js +4 -2
  270. package/dist/frontend/lowering/builtins/workers.js.map +1 -1
  271. package/dist/frontend/lowering/call-arguments.js +96 -4
  272. package/dist/frontend/lowering/call-arguments.js.map +1 -1
  273. package/dist/frontend/lowering/class-assertions.d.ts +8 -0
  274. package/dist/frontend/lowering/class-assertions.js +217 -1
  275. package/dist/frontend/lowering/class-assertions.js.map +1 -1
  276. package/dist/frontend/lowering/class-dynamic-dispatch.js +8 -5
  277. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  278. package/dist/frontend/lowering/class-method-mutations.js +88 -0
  279. package/dist/frontend/lowering/class-method-mutations.js.map +1 -1
  280. package/dist/frontend/lowering/coercions/state.d.ts +6 -0
  281. package/dist/frontend/lowering/coercions/state.js +2 -0
  282. package/dist/frontend/lowering/coercions/state.js.map +1 -1
  283. package/dist/frontend/lowering/coercions/unions.d.ts +8 -0
  284. package/dist/frontend/lowering/coercions/unions.js +67 -2
  285. package/dist/frontend/lowering/coercions/unions.js.map +1 -1
  286. package/dist/frontend/lowering/collation-repertoire.d.ts +1 -0
  287. package/dist/frontend/lowering/collation-repertoire.js +19 -0
  288. package/dist/frontend/lowering/collation-repertoire.js.map +1 -0
  289. package/dist/frontend/lowering/construction-escapes.d.ts +38 -0
  290. package/dist/frontend/lowering/construction-escapes.js +146 -0
  291. package/dist/frontend/lowering/construction-escapes.js.map +1 -0
  292. package/dist/frontend/lowering/construction-escapes.test.d.ts +1 -0
  293. package/dist/frontend/lowering/construction-escapes.test.js +150 -0
  294. package/dist/frontend/lowering/construction-escapes.test.js.map +1 -0
  295. package/dist/frontend/lowering/containers/array-callbacks.js +81 -44
  296. package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
  297. package/dist/frontend/lowering/containers/array-construction.js +15 -2
  298. package/dist/frontend/lowering/containers/array-construction.js.map +1 -1
  299. package/dist/frontend/lowering/containers/array-methods.js +231 -12
  300. package/dist/frontend/lowering/containers/array-methods.js.map +1 -1
  301. package/dist/frontend/lowering/containers/bytes.js +15 -4
  302. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  303. package/dist/frontend/lowering/containers/callback-arguments.js +43 -1
  304. package/dist/frontend/lowering/containers/callback-arguments.js.map +1 -1
  305. package/dist/frontend/lowering/containers/string-and-regexp.js +7 -63
  306. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  307. package/dist/frontend/lowering/cycle-initialization.d.ts +6 -1
  308. package/dist/frontend/lowering/cycle-initialization.js +59 -33
  309. package/dist/frontend/lowering/cycle-initialization.js.map +1 -1
  310. package/dist/frontend/lowering/divergences.d.ts +9 -0
  311. package/dist/frontend/lowering/divergences.js +630 -0
  312. package/dist/frontend/lowering/divergences.js.map +1 -0
  313. package/dist/frontend/lowering/expressions/object-literals.js +40 -2
  314. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  315. package/dist/frontend/lowering/expressions/union-fields.d.ts +19 -0
  316. package/dist/frontend/lowering/expressions/union-fields.js +236 -0
  317. package/dist/frontend/lowering/expressions/union-fields.js.map +1 -0
  318. package/dist/frontend/lowering/lower-calls.d.ts +5 -0
  319. package/dist/frontend/lowering/lower-calls.js +237 -158
  320. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  321. package/dist/frontend/lowering/lower-classes.d.ts +4 -0
  322. package/dist/frontend/lowering/lower-classes.js +72 -22
  323. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  324. package/dist/frontend/lowering/lower-exprs.d.ts +19 -0
  325. package/dist/frontend/lowering/lower-exprs.js +592 -109
  326. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  327. package/dist/frontend/lowering/lower-generators.d.ts +19 -13
  328. package/dist/frontend/lowering/lower-generators.js +67 -44
  329. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  330. package/dist/frontend/lowering/lower-inspect.js +3 -2
  331. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  332. package/dist/frontend/lowering/lower-island.d.ts +1 -1
  333. package/dist/frontend/lowering/lower-island.js +10 -7
  334. package/dist/frontend/lowering/lower-island.js.map +1 -1
  335. package/dist/frontend/lowering/lower-modules.js +90 -1
  336. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  337. package/dist/frontend/lowering/lower-stmts.js +47 -7
  338. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  339. package/dist/frontend/lowering/lowerer.d.ts +83 -2
  340. package/dist/frontend/lowering/lowerer.js +1158 -79
  341. package/dist/frontend/lowering/lowerer.js.map +1 -1
  342. package/dist/frontend/lowering/nan-coded-reads.d.ts +161 -0
  343. package/dist/frontend/lowering/nan-coded-reads.js +1342 -0
  344. package/dist/frontend/lowering/nan-coded-reads.js.map +1 -0
  345. package/dist/frontend/lowering/runtime-optional-bounds.d.ts +31 -0
  346. package/dist/frontend/lowering/runtime-optional-bounds.js +360 -0
  347. package/dist/frontend/lowering/runtime-optional-bounds.js.map +1 -0
  348. package/dist/frontend/lowering/runtime-optional-bounds.test.d.ts +1 -0
  349. package/dist/frontend/lowering/runtime-optional-bounds.test.js +94 -0
  350. package/dist/frontend/lowering/runtime-optional-bounds.test.js.map +1 -0
  351. package/dist/frontend/lowering/runtime-optional-elements.d.ts +117 -0
  352. package/dist/frontend/lowering/runtime-optional-elements.js +738 -0
  353. package/dist/frontend/lowering/runtime-optional-elements.js.map +1 -0
  354. package/dist/frontend/lowering/runtime-optional-guards.d.ts +36 -0
  355. package/dist/frontend/lowering/runtime-optional-guards.js +375 -0
  356. package/dist/frontend/lowering/runtime-optional-guards.js.map +1 -0
  357. package/dist/frontend/lowering/runtime-optional-guards.test.d.ts +1 -0
  358. package/dist/frontend/lowering/runtime-optional-guards.test.js +92 -0
  359. package/dist/frontend/lowering/runtime-optional-guards.test.js.map +1 -0
  360. package/dist/frontend/lowering/runtime-optional-ownership.d.ts +63 -0
  361. package/dist/frontend/lowering/runtime-optional-ownership.js +382 -0
  362. package/dist/frontend/lowering/runtime-optional-ownership.js.map +1 -0
  363. package/dist/frontend/lowering/runtime-optional-provenance.d.ts +2 -1
  364. package/dist/frontend/lowering/runtime-optional-provenance.js +2 -1
  365. package/dist/frontend/lowering/runtime-optional-provenance.js.map +1 -1
  366. package/dist/frontend/lowering/string-index-bounds.d.ts +36 -0
  367. package/dist/frontend/lowering/string-index-bounds.js +537 -0
  368. package/dist/frontend/lowering/string-index-bounds.js.map +1 -0
  369. package/dist/frontend/lowering/string-index-bounds.test.d.ts +1 -0
  370. package/dist/frontend/lowering/string-index-bounds.test.js +223 -0
  371. package/dist/frontend/lowering/string-index-bounds.test.js.map +1 -0
  372. package/dist/frontend/lowering/surfaces.js +8 -0
  373. package/dist/frontend/lowering/surfaces.js.map +1 -1
  374. package/dist/frontend/lowering/union-narrow.d.ts +2 -0
  375. package/dist/frontend/lowering/union-narrow.js +10 -6
  376. package/dist/frontend/lowering/union-narrow.js.map +1 -1
  377. package/dist/frontend/program-analysis.d.ts +10 -0
  378. package/dist/frontend/program-analysis.js +7 -0
  379. package/dist/frontend/program-analysis.js.map +1 -1
  380. package/dist/frontend/program.d.ts +25 -0
  381. package/dist/frontend/program.js +613 -17
  382. package/dist/frontend/program.js.map +1 -1
  383. package/dist/frontend/program.test.js +64 -1
  384. package/dist/frontend/program.test.js.map +1 -1
  385. package/dist/frontend/resolve.d.ts +6 -0
  386. package/dist/frontend/resolve.js +14 -0
  387. package/dist/frontend/resolve.js.map +1 -1
  388. package/dist/frontend/threads-import.d.ts +5 -0
  389. package/dist/frontend/threads-import.js +21 -0
  390. package/dist/frontend/threads-import.js.map +1 -0
  391. package/dist/frontend/type-mapper.d.ts +3 -0
  392. package/dist/frontend/type-mapper.js +72 -6
  393. package/dist/frontend/type-mapper.js.map +1 -1
  394. package/dist/frontend/worker-target.d.ts +4 -0
  395. package/dist/frontend/worker-target.js +8 -1
  396. package/dist/frontend/worker-target.js.map +1 -1
  397. package/dist/index.d.ts +7 -2
  398. package/dist/index.js +67 -17
  399. package/dist/index.js.map +1 -1
  400. package/dist/ir/build.d.ts +5 -0
  401. package/dist/ir/build.js +7 -0
  402. package/dist/ir/build.js.map +1 -1
  403. package/dist/ir/builtin-signatures.d.ts +1 -1
  404. package/dist/ir/builtin-signatures.js +5 -0
  405. package/dist/ir/builtin-signatures.js.map +1 -1
  406. package/dist/ir/constant-globals.d.ts +14 -0
  407. package/dist/ir/constant-globals.js +81 -0
  408. package/dist/ir/constant-globals.js.map +1 -0
  409. package/dist/ir/constant-globals.test.d.ts +1 -0
  410. package/dist/ir/constant-globals.test.js +97 -0
  411. package/dist/ir/constant-globals.test.js.map +1 -0
  412. package/dist/ir/final-fields.d.ts +35 -0
  413. package/dist/ir/final-fields.js +187 -0
  414. package/dist/ir/final-fields.js.map +1 -0
  415. package/dist/ir/final-fields.test.d.ts +1 -0
  416. package/dist/ir/final-fields.test.js +106 -0
  417. package/dist/ir/final-fields.test.js.map +1 -0
  418. package/dist/ir/int32-slots.d.ts +81 -0
  419. package/dist/ir/int32-slots.js +850 -0
  420. package/dist/ir/int32-slots.js.map +1 -0
  421. package/dist/ir/int32-slots.test.d.ts +1 -0
  422. package/dist/ir/int32-slots.test.js +249 -0
  423. package/dist/ir/int32-slots.test.js.map +1 -0
  424. package/dist/ir/integer-loops.d.ts +5 -0
  425. package/dist/ir/integer-loops.js +20 -4
  426. package/dist/ir/integer-loops.js.map +1 -1
  427. package/dist/ir/integer-loops.test.js +17 -0
  428. package/dist/ir/integer-loops.test.js.map +1 -1
  429. package/dist/ir/integer-ranges.d.ts +19 -3
  430. package/dist/ir/integer-ranges.js +168 -23
  431. package/dist/ir/integer-ranges.js.map +1 -1
  432. package/dist/ir/integer-ranges.test.js +74 -2
  433. package/dist/ir/integer-ranges.test.js.map +1 -1
  434. package/dist/ir/ir.d.ts +30 -7
  435. package/dist/ir/ir.js +4 -0
  436. package/dist/ir/ir.js.map +1 -1
  437. package/dist/ir/serialize.d.ts +12 -2
  438. package/dist/ir/serialize.js +190 -39
  439. package/dist/ir/serialize.js.map +1 -1
  440. package/dist/ir/serialize.test.js +65 -1
  441. package/dist/ir/serialize.test.js.map +1 -1
  442. package/dist/ir/validate.js +21 -2
  443. package/dist/ir/validate.js.map +1 -1
  444. package/dist/ir/validate.test.js +39 -0
  445. package/dist/ir/validate.test.js.map +1 -1
  446. package/dist/native/cache.d.ts +11 -1
  447. package/dist/native/cache.js +87 -2
  448. package/dist/native/cache.js.map +1 -1
  449. package/dist/native/cache.test.js +32 -1
  450. package/dist/native/cache.test.js.map +1 -1
  451. package/dist/native/cli.js +1 -1
  452. package/dist/native/cli.js.map +1 -1
  453. package/dist/native/compiler.d.ts +5 -0
  454. package/dist/native/compiler.js +55 -7
  455. package/dist/native/compiler.js.map +1 -1
  456. package/dist/native/prepare.d.ts +7 -1
  457. package/dist/native/prepare.js +65 -29
  458. package/dist/native/prepare.js.map +1 -1
  459. package/dist/native/prepare.test.js +23 -1
  460. package/dist/native/prepare.test.js.map +1 -1
  461. package/dist/native/text-file.d.ts +10 -0
  462. package/dist/native/text-file.js +41 -0
  463. package/dist/native/text-file.js.map +1 -0
  464. package/dist/startup-cache.d.ts +2 -0
  465. package/dist/startup-cache.js +2 -0
  466. package/dist/startup-cache.js.map +1 -1
  467. package/dist/text-parts.d.ts +5 -0
  468. package/dist/text-parts.js +36 -0
  469. package/dist/text-parts.js.map +1 -0
  470. package/package.json +20 -20
  471. package/surface-manifest.json +7 -1
  472. package/dist/frontend/lowering/expressions/union-field-write.d.ts +0 -8
  473. package/dist/frontend/lowering/expressions/union-field-write.js +0 -108
  474. package/dist/frontend/lowering/expressions/union-field-write.js.map +0 -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,9 +18,9 @@ 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
- import { lowerUnionFieldWrite } from "./expressions/union-field-write.js";
23
+ import { lowerUnionFieldRead, lowerUnionFieldWrite } from "./expressions/union-fields.js";
23
24
  import { captureContextArguments } from "./function-context.js";
24
25
  import { OBJECT_CALLABLE_VALUES } from "./surfaces.js";
25
26
  import { wasiGuestPath } from "../../wasi-paths.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";
@@ -166,7 +167,14 @@ export function lowerExpr(lowerer, expr) {
166
167
  }
167
168
  lowerExprDepth++;
168
169
  try {
169
- const lowered = lowerExprInner(lowerer, expr);
170
+ let lowered = lowerExprInner(lowerer, expr);
171
+ const nanCoded = lowerer.nanCodedReads;
172
+ if (nanCoded) {
173
+ if (lowered.type.kind === "f64" && nanCoded.reboxes(expr))
174
+ lowered = reboxNanCoded(lowerer, lowered, locOf(expr));
175
+ else if (lowered.type.kind === "union" && nanCoded.convertsSource(expr))
176
+ lowered = lowerOptionalNumber(lowerer, lowered, locOf(expr));
177
+ }
170
178
  if (lowered.type.kind === "void" && (lowerer.typeOf(expr).flags & ts.TypeFlags.Never) !== 0)
171
179
  lowerer.neverValued.add(lowered);
172
180
  return lowered;
@@ -175,6 +183,27 @@ export function lowerExpr(lowerer, expr) {
175
183
  lowerExprDepth--;
176
184
  }
177
185
  }
186
+ /** `number | undefined` from a NaN-coded double whose slot never holds a
187
+ * genuine NaN (nan-coded-reads.ts): NaN is exactly undefined. */
188
+ function reboxNanCoded(lowerer, value, loc) {
189
+ const optional = lowerer.withUndefinedArm(F64);
190
+ const stmts = [];
191
+ let stable = value;
192
+ if (value.kind !== "varRef") {
193
+ const tmp = lowerer.declareHiddenLocal("%nanCoded", F64);
194
+ stmts.push({ kind: "varDecl", localId: tmp.id, init: value, loc });
195
+ stable = varRef(tmp.id, F64, loc);
196
+ }
197
+ const result = {
198
+ kind: "ternary",
199
+ cond: { kind: "libCall", fn: "num.isNaN", args: [stable], type: BOOL, loc },
200
+ then: lowerer.wrappedUndefined(optional, loc),
201
+ else_: lowerer.coerceToExpected(stable, optional),
202
+ type: optional,
203
+ loc,
204
+ };
205
+ return stmts.length === 0 ? result : { kind: "seqExpr", stmts, result, type: optional, loc };
206
+ }
178
207
  function lowerExprInner(lowerer, expr) {
179
208
  const loc = locOf(expr);
180
209
  // An optional chain's guarded receiver: already evaluated by the
@@ -294,6 +323,14 @@ function lowerExprInner(lowerer, expr) {
294
323
  // traps. Sub-union assertions and non-union inners keep their
295
324
  // historic erasure (the widening sites re-tag with traps already).
296
325
  if (ts.isNonNullExpression(expr)) {
326
+ // An asserted element read forwarded into a slot that holds undefined
327
+ // (see analyzeRuntimeOptionalArrayReads) reads without the bounds trap.
328
+ if (lowerer.runtimeOptionalAssertions.has(expr) &&
329
+ ts.isElementAccessExpression(expr.expression)) {
330
+ const probe = lowerAbsenceProbe(lowerer, expr.expression);
331
+ if (probe?.type.kind === "union")
332
+ return probe;
333
+ }
297
334
  const inner = lowerer.lowerExpr(expr.expression);
298
335
  if (inner.type.kind === "union") {
299
336
  // `!` performs no runtime check: a missing array element stays
@@ -301,14 +338,20 @@ function lowerExprInner(lowerer, expr) {
301
338
  if (ts.isElementAccessExpression(expr.expression) &&
302
339
  assertedElementKeepsUndefined(lowerer, expr))
303
340
  return inner;
341
+ // A forwarded assertion whose destination was promoted to hold
342
+ // undefined (see analyzeRuntimeOptionalArrayReads), or an equality
343
+ // operand, keeps the value: `!` performs no runtime check.
344
+ const target = lowerer.mapTypeOf(lowerer.typeOf(expr));
345
+ if (lowerer.runtimeOptionalAssertions.has(expr) ||
346
+ (target?.kind === "object" && isEqualityOperand(expr)))
347
+ return inner;
304
348
  const use = runtimeOptionalUseOf(expr);
305
349
  if (runtimeOptionalAssertionErases(lowerer, expr, inner, use))
306
350
  return inner;
307
- const target = lowerer.mapTypeOf(lowerer.typeOf(expr));
308
351
  if (target && target.kind !== "union" && !typeEquals(target, inner.type)) {
309
352
  const helper = lowerer.narrowedArmHelper(inner.type.unionId, target, loc);
310
353
  if (helper) {
311
- return { kind: "call", callee: helper, args: [inner], type: target, loc };
354
+ return lowerer.checkedNarrowCall(helper, inner, target, loc);
312
355
  }
313
356
  }
314
357
  return inner;
@@ -730,7 +773,7 @@ function lowerExprInner(lowerer, expr) {
730
773
  // A known static result type fixes typeof's answer, but its producer
731
774
  // still evaluates: calls, getters, and checked reads can have effects
732
775
  // or throw. Only trivial operands may disappear.
733
- let operand = lowerer.lowerExpr(expr.expression);
776
+ let operand = deferredSlotOr(lowerer, runtimeOptionalStorageOperand(lowerer, expr.expression) ?? lowerer.lowerExpr(expr.expression));
734
777
  if (operand.type.kind === "jsval") {
735
778
  return { kind: "jsOp", op: "typeof", args: [operand], type: STRING, loc };
736
779
  }
@@ -949,13 +992,7 @@ function lowerExprInner(lowerer, expr) {
949
992
  ? lowerer.narrowedArmHelper(local.type.unionId, narrowed, loc)
950
993
  : null;
951
994
  if (helper) {
952
- return {
953
- kind: "call",
954
- callee: helper,
955
- args: [varRef(local.id, local.type, loc)],
956
- type: narrowed,
957
- loc,
958
- };
995
+ return lowerer.checkedNarrowCall(helper, varRef(local.id, local.type, loc), narrowed, loc);
959
996
  }
960
997
  }
961
998
  }
@@ -993,7 +1030,10 @@ function lowerExprInner(lowerer, expr) {
993
1030
  // that does not exist. The blocked-binding cascade names the use;
994
1031
  // without this the validator's registration check ICEs on the live
995
1032
  // reference (`@this {T}` inference — signature 07).
996
- if (lowerer.typeNamesUnregisteredClass(g.type)) {
1033
+ const unregistered = lowerer.unregisteredClassOf(g.type, new Set());
1034
+ if (unregistered !== null) {
1035
+ // The class's own rejection is the root cause the cascade names.
1036
+ lowerer.flushDeferredClass(unregistered);
997
1037
  lowerer.pushDiag(blockedBindingUseDiag(expr.text, loc));
998
1038
  throw new PoisonError();
999
1039
  }
@@ -1026,7 +1066,7 @@ function lowerExprInner(lowerer, expr) {
1026
1066
  lowerer.armTag(g.type.unionId, narrowed) >= 0) {
1027
1067
  const helper = lowerer.narrowedArmHelper(g.type.unionId, narrowed, loc);
1028
1068
  if (helper)
1029
- return { kind: "call", callee: helper, args: [ref], type: narrowed, loc };
1069
+ return lowerer.checkedNarrowCall(helper, ref, narrowed, loc);
1030
1070
  }
1031
1071
  const use = runtimeOptionalUseOf(expr);
1032
1072
  // The enclosing logical/conditional expression consumes the union
@@ -1124,6 +1164,14 @@ function lowerExprInner(lowerer, expr) {
1124
1164
  // as interned string literals; functions have no closure
1125
1165
  // representation (they lower to libCall at call sites only); members
1126
1166
  // with no lowering at all fence with the module-qualified name.
1167
+ {
1168
+ const member = threadsImportOf(lowerer.program, expr);
1169
+ // scriptc delivers published graphs by reference.
1170
+ if (member === "sharesPublishedGraphs")
1171
+ return { kind: "boolLit", value: true, type: BOOL, loc };
1172
+ if (member === "publish")
1173
+ lowerer.noLowering("publish (@scriptc/threads) as a value", expr, "call publish(value) directly");
1174
+ }
1127
1175
  {
1128
1176
  const bi = lowerer.builtinImportOf(expr);
1129
1177
  if (bi) {
@@ -2189,6 +2237,11 @@ function lowerExprInner(lowerer, expr) {
2189
2237
  handled.kind === "recordGet" &&
2190
2238
  lowerer.isRuntimeOptionalField(handled.shapeId, handled.field))
2191
2239
  return handled;
2240
+ // A class field assigned a missing read: the checker narrows this
2241
+ // read to the assigned value's bare type, but the stored undefined
2242
+ // arm is real (`obj.n = bytes[i]; obj.n` is undefined in Node).
2243
+ if (runtimeOptionalClassField(lowerer, handled, expr))
2244
+ return handled;
2192
2245
  return lowerer.maybeNarrow(handled, expr);
2193
2246
  }
2194
2247
  // `globalThis.<name>` that no lowering above claimed
@@ -3299,13 +3352,7 @@ function runtimeOptionalReceiverRead(lowerer, expr, local, property, loc) {
3299
3352
  if (!helper) {
3300
3353
  lowerer.unsupported("SC1090", expr, "a direct read from a runtime-optional capture with multiple value arms");
3301
3354
  }
3302
- return {
3303
- kind: "call",
3304
- callee: helper,
3305
- args: [varRef(local.id, local.type, loc)],
3306
- type: narrowed,
3307
- loc,
3308
- };
3355
+ return lowerer.checkedNarrowCall(helper, varRef(local.id, local.type, loc), narrowed, loc);
3309
3356
  }
3310
3357
  // A predicate can strengthen a record's fields or narrow a base class
3311
3358
  // to a subclass without changing the slot's stored value arm. Extract
@@ -3438,6 +3485,18 @@ function runtimeOptionalElementKey(expr) {
3438
3485
  return expr.text;
3439
3486
  return null;
3440
3487
  }
3488
+ /** An operand of `===`, `!==`, `==` or `!=` (through parentheses). */
3489
+ function isEqualityOperand(node) {
3490
+ let outer = node;
3491
+ while (ts.isParenthesizedExpression(outer.parent))
3492
+ outer = outer.parent;
3493
+ const parent = outer.parent;
3494
+ return (ts.isBinaryExpression(parent) &&
3495
+ (parent.operatorToken.kind === ts.SyntaxKind.EqualsEqualsEqualsToken ||
3496
+ parent.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken ||
3497
+ parent.operatorToken.kind === ts.SyntaxKind.EqualsEqualsToken ||
3498
+ parent.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsToken));
3499
+ }
3441
3500
  /** Whether `xs[i]!` lands where an absent element's undefined is
3442
3501
  * representable: array storage (a literal element, a push/unshift
3443
3502
  * argument, an element assignment — arrays record the undefined state),
@@ -3505,6 +3564,17 @@ export function lowerUnitComparison(lowerer, left, right, negated, loc) {
3505
3564
  // Two unit literals (`undefined === undefined`): statically decided.
3506
3565
  return { kind: "boolLit", value: (other.unit === unit.unit) !== negated, type: BOOL, loc };
3507
3566
  }
3567
+ const slot = lowerer.deferredFieldSlot(other);
3568
+ if (slot)
3569
+ return lowerUnitComparison(lowerer, slot, unit, negated, loc);
3570
+ // A binding the checker narrowed past the unit can still hold it at
3571
+ // runtime when its value came from an unassigned deferred-init field;
3572
+ // the stored tag answers either way.
3573
+ if (other.kind === "unionNarrow" &&
3574
+ other.value.kind === "varRef" &&
3575
+ other.value.type.kind === "union" &&
3576
+ lowerer.armTag(other.value.type.unionId, unit.type) >= 0)
3577
+ return lowerUnitComparison(lowerer, other.value, unit, negated, loc);
3508
3578
  if (other.type.kind === "union") {
3509
3579
  const tag = lowerer.armTag(other.type.unionId, unit.type);
3510
3580
  if (tag < 0) {
@@ -3612,7 +3682,7 @@ function lowerLooseNullCompare(lowerer, expr, loc) {
3612
3682
  if (!leftIsNull && right.kind !== ts.SyntaxKind.NullKeyword)
3613
3683
  return null;
3614
3684
  const otherNode = leftIsNull ? right : left;
3615
- const other = lowerer.lowerExpr(otherNode);
3685
+ const other = lowerPresenceOperand(lowerer, otherNode);
3616
3686
  if (isUnitType(other.type)) {
3617
3687
  // `null == null`, `undefined == null`: units are mutually loose-equal.
3618
3688
  return { kind: "boolLit", value: !negated, type: BOOL, loc };
@@ -3717,13 +3787,84 @@ export function lowerNullishCoalesce(lowerer, expr, loc) {
3717
3787
  parents.push(first);
3718
3788
  first = first.left;
3719
3789
  }
3720
- let result = lowerNullishPair(lowerer, first, first === expr ? loc : locOf(first), lowerAbsenceProbe(lowerer, first.left) ?? lowerer.lowerExpr(first.left));
3790
+ let result = lowerNullishPair(lowerer, first, first === expr ? loc : locOf(first), assertedPresenceOperand(lowerer, first.left));
3721
3791
  for (let i = parents.length - 1; i >= 0; i--) {
3722
3792
  const parent = parents[i];
3723
3793
  result = lowerNullishPair(lowerer, parent, parent === expr ? loc : locOf(parent), result);
3724
3794
  }
3725
3795
  return result;
3726
3796
  }
3797
+ /** The left side of `??` (see lowerPresenceOperand). The absence probe
3798
+ * reads optional storage beneath erased assertions; a union assertion that
3799
+ * narrows a stored class arm still applies its checked class view, so
3800
+ * `(node.parent as Sub | undefined) ?? node` sees the asserted arm on both
3801
+ * sides of the default. */
3802
+ function assertedPresenceOperand(lowerer, node) {
3803
+ const probe = lowerAbsenceProbe(lowerer, node);
3804
+ if (probe === null)
3805
+ return runtimeOptionalStorageOperand(lowerer, node) ?? lowerer.lowerExpr(node);
3806
+ if (probe.type.kind !== "union" && probe.type.kind !== "object")
3807
+ return probe;
3808
+ let outer = node;
3809
+ while (ts.isParenthesizedExpression(outer))
3810
+ outer = outer.expression;
3811
+ if (!ts.isAsExpression(outer) && !ts.isTypeAssertion(outer))
3812
+ return probe;
3813
+ const target = lowerer.mapTypeOf(lowerer.checker.getTypeFromTypeNode(outer.type));
3814
+ if (target?.kind !== "union" || typeEquals(target, probe.type))
3815
+ return probe;
3816
+ return checkedClassUnionAssertion(lowerer, probe, target, locOf(outer)) ?? probe;
3817
+ }
3818
+ /** Read-modify-write updates read the member first: an unassigned
3819
+ * deferred-init receiver throws Node's member-read TypeError. */
3820
+ function checkDeferredMemberReceiver(lowerer, target, access) {
3821
+ if (target.container !== "class" ||
3822
+ !ts.isPropertyAccessExpression(access) ||
3823
+ target.obj.type.kind !== "object" ||
3824
+ lowerer.deferredFieldSlot(target.obj) === null)
3825
+ return;
3826
+ target.obj =
3827
+ lowerer.runtimeOptionalPropertyReceiver(access.expression, target.obj, target.obj.type, target.field) ?? target.obj;
3828
+ }
3829
+ /** Whether evaluating `expr` cannot store anything or run other code:
3830
+ * reads, arithmetic, tests and checked extractions (which at most throw). */
3831
+ function writeFree(expr) {
3832
+ switch (expr.kind) {
3833
+ case "numLit":
3834
+ case "strLit":
3835
+ case "boolLit":
3836
+ case "unitLit":
3837
+ case "varRef":
3838
+ return true;
3839
+ case "fieldGet":
3840
+ case "recordGet":
3841
+ return writeFree(expr.obj);
3842
+ case "bin":
3843
+ case "logical":
3844
+ return writeFree(expr.left) && writeFree(expr.right);
3845
+ case "unary":
3846
+ case "toBool":
3847
+ return writeFree(expr.operand);
3848
+ case "ternary":
3849
+ return writeFree(expr.cond) && writeFree(expr.then) && writeFree(expr.else_);
3850
+ case "unionIsTag":
3851
+ case "unionNarrow":
3852
+ case "unionWrap":
3853
+ return writeFree(expr.value);
3854
+ case "libCall":
3855
+ return expr.fn === "error.nodeThrow";
3856
+ default:
3857
+ return false;
3858
+ }
3859
+ }
3860
+ /** The TypeError of a deferred-init field read that finds the field
3861
+ * unassigned where its declared type cannot hold undefined. */
3862
+ export const DEFERRED_READ_MESSAGE = "undefined is not representable in the target union (a value narrowed or asserted past it still held it)";
3863
+ /** The undefined-armed slot behind a checked deferred-init field read, or
3864
+ * the value itself (Lowerer.deferredFieldSlot). */
3865
+ function deferredSlotOr(lowerer, value) {
3866
+ return lowerer.deferredFieldSlot(value) ?? value;
3867
+ }
3727
3868
  /** A plain value read that may be runtime-optional: an unchecked element
3728
3869
  * read, or a binding, member or call that carries one. Lowering these
3729
3870
  * without a destination type is the same as lowering them into one. */
@@ -3844,6 +3985,24 @@ function lowerNullishPair(lowerer, expr, loc, left) {
3844
3985
  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
3986
  }
3846
3987
  }
3988
+ // A subclass value defaulted to a base-class value (`circle ?? shape`):
3989
+ // the present arm upcasts after the original nullish test, and the
3990
+ // default lowers lazily into the base-class result.
3991
+ const present = rest.length === 1 ? rest[0] : null;
3992
+ if (present?.kind === "object" &&
3993
+ type.kind === "object" &&
3994
+ present.className !== type.className &&
3995
+ lowerer.isSubclassOf(present.className, type.className)) {
3996
+ const helper = lowerer.narrowedArmHelper(left.type.unionId, present, loc);
3997
+ if (helper !== null) {
3998
+ return nullishBranches(lowerer, left, left.type, def.arms, type, loc, () => lowerer.lowerExprExpecting(expr.right, type), (stable) => ({
3999
+ kind: "upcast",
4000
+ value: { kind: "call", callee: helper, args: [stable], type: present, loc },
4001
+ type,
4002
+ loc,
4003
+ }));
4004
+ }
4005
+ }
3847
4006
  // A default may change the union or widen its records. Test the
3848
4007
  // original tag before coercing: converting the whole left first can
3849
4008
  // lose nullish arms, and evaluating the default eagerly loses laziness.
@@ -3957,7 +4116,7 @@ export function lowerCondition(lowerer, expr) {
3957
4116
  };
3958
4117
  }
3959
4118
  }
3960
- const value = lowerAbsenceProbe(lowerer, expr) ?? lowerer.lowerExpr(expr);
4119
+ const value = lowerPresenceOperand(lowerer, expr);
3961
4120
  return (tryLowerIndexTruthiness(lowerer, value, expr, locOf(expr)) ?? lowerer.ensureBool(value, expr));
3962
4121
  }
3963
4122
  function lowerPromiseThenPresence(lowerer, access, result) {
@@ -3997,13 +4156,7 @@ function lowerPromiseThenPresence(lowerer, access, result) {
3997
4156
  const helper = lowerer.narrowedArmHelper(receiver.type.unionId, promiseType, receiver.loc);
3998
4157
  if (helper === null)
3999
4158
  return null;
4000
- receiver = {
4001
- kind: "call",
4002
- callee: helper,
4003
- args: [receiver],
4004
- type: promiseType,
4005
- loc: receiver.loc,
4006
- };
4159
+ receiver = lowerer.checkedNarrowCall(helper, receiver, promiseType, receiver.loc);
4007
4160
  }
4008
4161
  }
4009
4162
  if (receiver.type.kind === "dyn") {
@@ -4691,13 +4844,7 @@ export function lowerIntrinsicProperty(lowerer, expr) {
4691
4844
  ? lowerer.narrowedArmHelper(receiver.type.unionId, present, locOf(expr.expression))
4692
4845
  : null;
4693
4846
  receiver = helper
4694
- ? {
4695
- kind: "call",
4696
- callee: helper,
4697
- args: [receiver],
4698
- type: present,
4699
- loc: locOf(expr.expression),
4700
- }
4847
+ ? lowerer.checkedNarrowCall(helper, receiver, present, locOf(expr.expression))
4701
4848
  : lowerer.maybeNarrow(receiver, expr.expression);
4702
4849
  }
4703
4850
  // An island handle behind a typed-array .d.ts surface: the engine
@@ -4791,13 +4938,7 @@ export function lowerIntrinsicProperty(lowerer, expr) {
4791
4938
  ? lowerer.narrowedArmHelper(receiver.type.unionId, present, locOf(expr.expression))
4792
4939
  : null;
4793
4940
  receiver = helper
4794
- ? {
4795
- kind: "call",
4796
- callee: helper,
4797
- args: [receiver],
4798
- type: present,
4799
- loc: locOf(expr.expression),
4800
- }
4941
+ ? lowerer.checkedNarrowCall(helper, receiver, present, locOf(expr.expression))
4801
4942
  : lowerer.maybeNarrow(receiver, expr.expression);
4802
4943
  }
4803
4944
  // An island handle behind an array-typed .d.ts surface
@@ -5097,7 +5238,30 @@ export function lowerArrayLiteral(lowerer, expr, expected) {
5097
5238
  }
5098
5239
  lowerer.badType(expr, tsType);
5099
5240
  }
5100
- const type = mapped;
5241
+ let type = mapped;
5242
+ // An inferred array of records takes the layout of an element literal
5243
+ // whose fields widened for missing-element reads; the other elements
5244
+ // build that layout directly. An explicit destination keeps its own.
5245
+ if (!expected && type.elem.kind === "record") {
5246
+ let variant = null;
5247
+ for (const candidate of expr.elements) {
5248
+ let x = candidate;
5249
+ while (ts.isParenthesizedExpression(x))
5250
+ x = x.expression;
5251
+ if (!ts.isObjectLiteralExpression(x))
5252
+ continue;
5253
+ const probe = tryLowerExpression(lowerer, x);
5254
+ if (!probe || !lowerer.isRuntimeOptionalRecordVariant(probe.type, type.elem))
5255
+ continue;
5256
+ if (variant !== null && !typeEquals(variant, probe.type)) {
5257
+ variant = null;
5258
+ break;
5259
+ }
5260
+ variant = probe.type;
5261
+ }
5262
+ if (variant !== null)
5263
+ type = arrayOf(variant);
5264
+ }
5101
5265
  // Keep the array payload type fixed. Optional reads are stored through
5102
5266
  // arrayValueStore, which records UNDEFINED in the state byte while the
5103
5267
  // payload remains number/string/etc.; widening the array element here
@@ -5262,8 +5426,21 @@ export function lowerArrayLiteral(lowerer, expr, expected) {
5262
5426
  }
5263
5427
  const out = lowerer.declareHiddenLocal("%arrayLit", type);
5264
5428
  const outRef = varRef(out.id, type, loc);
5429
+ // Dense capacity for the elements the statements below store.
5430
+ const capacity = Math.min(elems.length - spreads.length, 1024);
5265
5431
  const body = [
5266
- { kind: "varDecl", localId: out.id, init: { kind: "arrayLit", elems: [], type, loc }, loc },
5432
+ {
5433
+ kind: "varDecl",
5434
+ localId: out.id,
5435
+ init: {
5436
+ kind: "arrayLit",
5437
+ elems: [],
5438
+ ...(capacity > 0 ? { capacity } : {}),
5439
+ type,
5440
+ loc,
5441
+ },
5442
+ loc,
5443
+ },
5267
5444
  ];
5268
5445
  const spreadSet = new Set(spreads);
5269
5446
  const currentLength = () => ({
@@ -5438,6 +5615,34 @@ export function lowerOptionalNumber(lowerer, operand, loc, narrowedNode) {
5438
5615
  ? value
5439
5616
  : { kind: "seqExpr", stmts: prefix, result: value, type: F64, loc };
5440
5617
  }
5618
+ /** A number argument of a builtin that converts it with ToNumber (Math
5619
+ * functions, String.fromCharCode, the global isNaN/isFinite, DataView
5620
+ * offsets and values). ToNumber(undefined) is NaN, so a missing value — an
5621
+ * out-of-range read, a local or field holding one, or a hole — converts to
5622
+ * NaN instead of trusting the checker's number type. */
5623
+ export function lowerToNumberArgument(lowerer, node) {
5624
+ let inner = node;
5625
+ while (ts.isParenthesizedExpression(inner))
5626
+ inner = inner.expression;
5627
+ const loc = locOf(inner);
5628
+ const isOptionalNumber = (value) => value.type.kind === "union" &&
5629
+ lowerer.armTag(value.type.unionId, UNDEFINED_T) >= 0 &&
5630
+ lowerer.stripUndefinedArm(value.type).kind === "f64";
5631
+ const optional = ts.isIdentifier(inner)
5632
+ ? runtimeOptionalStorageOperand(lowerer, inner)
5633
+ : ts.isElementAccessExpression(inner)
5634
+ ? lowerAbsenceProbe(lowerer, inner)
5635
+ : null;
5636
+ if (optional && isOptionalNumber(optional))
5637
+ return lowerOptionalNumber(lowerer, optional, loc, inner);
5638
+ // A conditional builds each branch for the destination.
5639
+ if (ts.isConditionalExpression(inner))
5640
+ return lowerer.lowerExprExpecting(node, F64);
5641
+ const value = lowerer.lowerExpr(node);
5642
+ if (isOptionalNumber(value))
5643
+ return lowerOptionalNumber(lowerer, value, loc, inner);
5644
+ return lowerer.coerceInto(node, value, F64);
5645
+ }
5441
5646
  /** `a[i]` reads. Only f64 indices into array receivers are modeled; JS
5442
5647
  * string-key element access (`a["length"]`) and string indexing (`s[0]`
5443
5648
  * typechecks against the lib's index signature; use .charAt) stay out. */
@@ -5686,7 +5891,7 @@ export function lowerElementAccess(lowerer, expr) {
5686
5891
  ? lowerer.narrowedArmHelper(recv.type.unionId, present, locOf(expr.expression))
5687
5892
  : null;
5688
5893
  recv = helper
5689
- ? { kind: "call", callee: helper, args: [recv], type: present, loc: locOf(expr.expression) }
5894
+ ? lowerer.checkedNarrowCall(helper, recv, present, locOf(expr.expression))
5690
5895
  : lowerer.maybeNarrow(recv, expr.expression);
5691
5896
  }
5692
5897
  // A typed-array .d.ts surface whose VALUE is an island handle
@@ -5719,14 +5924,24 @@ export function lowerElementAccess(lowerer, expr) {
5719
5924
  if (index.type.kind !== "f64") {
5720
5925
  lowerer.unsupported("SC1090", expr.argumentExpression, "indexing with non-number keys");
5721
5926
  }
5722
- return {
5723
- kind: "bytesIntrinsic",
5724
- method: "get",
5725
- receiver: recv,
5726
- args: [index],
5727
- type: F64,
5728
- loc: locOf(expr),
5729
- };
5927
+ // `t[i]!` asserts presence: the numeric element read (NaN when
5928
+ // invalid). Every other read answers undefined for an invalid index,
5929
+ // like Node.
5930
+ // A read whose every consumer treats undefined like NaN (see
5931
+ // nan-coded-reads.ts) is the same plain numeric read.
5932
+ if ((ts.isNonNullExpression(expr.parent) && expr.parent.expression === expr) ||
5933
+ lowerer.nanCodedReads?.isNumericRead(expr) === true) {
5934
+ return {
5935
+ kind: "bytesIntrinsic",
5936
+ method: "get",
5937
+ receiver: recv,
5938
+ args: [index],
5939
+ type: F64,
5940
+ loc: locOf(expr),
5941
+ invalidNaN: true,
5942
+ };
5943
+ }
5944
+ return lowerSafeBytesRead(lowerer, recv, index, locOf(expr));
5730
5945
  }
5731
5946
  // Tuple element read `t[0]`: a positional-field read of the tuple's
5732
5947
  // record shape — LITERAL indices only (the checker's per-index types
@@ -5769,13 +5984,7 @@ export function lowerElementAccess(lowerer, expr) {
5769
5984
  ? lowerer.narrowedArmHelper(obj.type.unionId, present, locOf(expr.expression))
5770
5985
  : null;
5771
5986
  obj = helper
5772
- ? {
5773
- kind: "call",
5774
- callee: helper,
5775
- args: [obj],
5776
- type: present,
5777
- loc: locOf(expr.expression),
5778
- }
5987
+ ? lowerer.checkedNarrowCall(helper, obj, present, locOf(expr.expression))
5779
5988
  : lowerer.maybeNarrow(obj, expr.expression);
5780
5989
  }
5781
5990
  const idx = tupleLiteralIndex(expr.argumentExpression);
@@ -5957,6 +6166,17 @@ export function lowerElementAccess(lowerer, expr) {
5957
6166
  const recv = lowerer.lowerExpr(expr.expression);
5958
6167
  const index = lowerOptionalNumber(lowerer, lowerer.lowerExpr(expr.argumentExpression), locOf(expr.argumentExpression), expr.argumentExpression);
5959
6168
  if (index.type.kind === "f64" && recv.type.kind === "string") {
6169
+ // A proven in-bounds integer index always names a code unit, where
6170
+ // charAt and the property read agree.
6171
+ if (lowerer.stringIndexBounds.inBounds(expr))
6172
+ return {
6173
+ kind: "strIntrinsic",
6174
+ method: "charAt",
6175
+ receiver: recv,
6176
+ args: [index],
6177
+ type: STRING,
6178
+ loc: locOf(expr),
6179
+ };
5960
6180
  return lowerOptionalStringIndex(lowerer, recv, index, lowerer.withUndefinedArm(STRING), locOf(expr));
5961
6181
  }
5962
6182
  lowerer.unsupported("SC1090", expr, "string indexing with this index/result shape (expected a number index and a string or string | undefined result)");
@@ -6020,7 +6240,7 @@ export function lowerElementAccess(lowerer, expr) {
6020
6240
  ? lowerer.narrowedArmHelper(arr.type.unionId, present, locOf(expr.expression))
6021
6241
  : null;
6022
6242
  arr = helper
6023
- ? { kind: "call", callee: helper, args: [arr], type: present, loc: locOf(expr.expression) }
6243
+ ? lowerer.checkedNarrowCall(helper, arr, present, locOf(expr.expression))
6024
6244
  : lowerer.maybeNarrow(arr, expr.expression);
6025
6245
  }
6026
6246
  // The checker sees an array but the VALUE is an island handle (an
@@ -6330,6 +6550,74 @@ function lowerRecordPropertyKey(lowerer, key, node) {
6330
6550
  }
6331
6551
  return key;
6332
6552
  }
6553
+ /** The stored value of an identifier whose storage holds an undefined arm
6554
+ * that the checker's type at this use has dropped. An assignment from an
6555
+ * unchecked indexed read narrows the declared type even though the value
6556
+ * can be absent at runtime, so presence tests (`=== undefined`, `== null`,
6557
+ * truthiness, `??`, `typeof`) read the storage tag instead of trusting
6558
+ * that narrowing. A guard-proven use answers the same way at runtime. */
6559
+ export function runtimeOptionalStorageOperand(lowerer, node) {
6560
+ let expr = node;
6561
+ while (ts.isParenthesizedExpression(expr))
6562
+ expr = expr.expression;
6563
+ if (!ts.isIdentifier(expr))
6564
+ return null;
6565
+ // Only storage that can actually receive an absent value without the
6566
+ // checker seeing it qualifies; other declared-optional bindings keep the
6567
+ // checker's assignment and guard narrowing.
6568
+ const symbol = lowerer.resolveValueSymbol(expr);
6569
+ const local = lowerer.resolveLocal(expr);
6570
+ const global = local ? undefined : lowerer.globalOf(expr);
6571
+ const root = local ? lowerer.runtimeOptionalRootOf(local) : null;
6572
+ if (root && lowerer.runtimeOptionalStorageLocals.has(root)) {
6573
+ // These locals track guards: a branch that proved presence removes
6574
+ // the binding from the active set, and its reads stay narrowed. A
6575
+ // captured binding can be reassigned between calls, so a capture
6576
+ // never inherits a guard (the identifier read's own rule).
6577
+ const captured = local.boxed === true ||
6578
+ (!!symbol && lowerer.ctx.captureBySymbol.get(symbol) === local) ||
6579
+ root !== local;
6580
+ if (!captured && !lowerer.runtimeOptionalLocals.has(root))
6581
+ return null;
6582
+ }
6583
+ else if (!(symbol && lowerer.runtimeOptionalAssignedSymbols.has(symbol)) &&
6584
+ !(symbol && lowerer.runtimeOptionalBindingTypes.has(symbol)) &&
6585
+ !(global && lowerer.isRuntimeOptionalGlobal(global)))
6586
+ return null;
6587
+ const optional = lowerer.runtimeOptionalIdentifierValue(expr);
6588
+ if (optional === null)
6589
+ return null;
6590
+ const checked = lowerer.mapTypeOf(lowerer.typeOf(expr));
6591
+ if (checked === null ||
6592
+ (checked.kind === "union" && lowerer.armTag(checked.unionId, UNDEFINED_T) >= 0))
6593
+ return null;
6594
+ return optional.value;
6595
+ }
6596
+ /** A `T | undefined` class field read that the checker narrowed to `T`
6597
+ * where the field was assigned a value that may be missing (an unchecked
6598
+ * indexed read). TypeScript's assignment narrowing is not a runtime fact
6599
+ * there, so the read keeps the stored union instead of extracting `T`. */
6600
+ function runtimeOptionalClassField(lowerer, value, node) {
6601
+ if (value.kind !== "fieldGet" || value.type.kind !== "union")
6602
+ return false;
6603
+ if (lowerer.armTag(value.type.unionId, UNDEFINED_T) < 0)
6604
+ return false;
6605
+ if ((lowerer.unions.get(value.type.unionId)?.arms.length ?? 0) !== 2)
6606
+ return false;
6607
+ const symbol = lowerer.checker.getSymbolAtLocation(node.name);
6608
+ if (!symbol || !lowerer.runtimeOptionalAssignedSymbols.has(symbol))
6609
+ return false;
6610
+ const narrowed = lowerer.mapTypeOf(lowerer.typeOf(node));
6611
+ return narrowed !== null && typeEquals(narrowed, lowerer.stripUndefinedArm(value.type));
6612
+ }
6613
+ /** A presence-test operand: an absence-aware element or field read, an
6614
+ * identifier's runtime-optional storage, or the ordinary lowering. */
6615
+ export function lowerPresenceOperand(lowerer, node) {
6616
+ // An unassigned deferred-init field observes its undefined slot too.
6617
+ return deferredSlotOr(lowerer, lowerAbsenceProbe(lowerer, node) ??
6618
+ runtimeOptionalStorageOperand(lowerer, node) ??
6619
+ lowerer.lowerExpr(node));
6620
+ }
6333
6621
  /** A keyed read used only to observe absence (`if (map[k])`, or the left
6334
6622
  * side of `||`/`??`). JavaScript answers undefined for missing record keys
6335
6623
  * and array indices even when noUncheckedIndexedAccess is disabled. Keep
@@ -6542,13 +6830,7 @@ export function lowerElementCompound(lowerer, expr, op) {
6542
6830
  ? lowerer.narrowedArmHelper(receiver.type.unionId, present, locOf(target.expression))
6543
6831
  : null;
6544
6832
  if (helper)
6545
- receiver = {
6546
- kind: "call",
6547
- callee: helper,
6548
- args: [receiver],
6549
- type: present,
6550
- loc: locOf(target.expression),
6551
- };
6833
+ receiver = lowerer.checkedNarrowCall(helper, receiver, present, locOf(target.expression));
6552
6834
  }
6553
6835
  if (receiver.type.kind !== receiverType.kind) {
6554
6836
  lowerer.unsupported("SC1090", target.expression, "compound assignment through a non-native array or byte view");
@@ -6563,12 +6845,15 @@ export function lowerElementCompound(lowerer, expr, op) {
6563
6845
  const oldValue = receiver.type.kind === "array"
6564
6846
  ? arrayValueRead(lowerer, receiverRef(), indexRef(), receiver.type.elem, locOf(target))
6565
6847
  : {
6848
+ // An invalid index reads undefined in Node, which every numeric
6849
+ // compound operator turns into NaN; the write is then ignored.
6566
6850
  kind: "bytesIntrinsic",
6567
6851
  method: "get",
6568
6852
  receiver: receiverRef(),
6569
6853
  args: [indexRef()],
6570
6854
  type: F64,
6571
6855
  loc: locOf(target),
6856
+ invalidNaN: true,
6572
6857
  };
6573
6858
  const oldLocal = lowerer.declareHiddenLocal("%compoundOld", oldValue.type);
6574
6859
  const oldRef = () => varRef(oldLocal.id, oldValue.type, loc);
@@ -7184,13 +7469,7 @@ export function lowerElementWrite(lowerer, expr) {
7184
7469
  ? lowerer.narrowedArmHelper(arr.type.unionId, present, locOf(target.expression))
7185
7470
  : null;
7186
7471
  if (helper) {
7187
- arr = {
7188
- kind: "call",
7189
- callee: helper,
7190
- args: [arr],
7191
- type: present,
7192
- loc: locOf(target.expression),
7193
- };
7472
+ arr = lowerer.checkedNarrowCall(helper, arr, present, locOf(target.expression));
7194
7473
  }
7195
7474
  }
7196
7475
  if (arr.type.kind !== "array") {
@@ -7308,7 +7587,7 @@ export function ensureString(lowerer, e, node) {
7308
7587
  narrowed.kind === "bigint")) {
7309
7588
  const helper = lowerer.narrowedArmHelper(e.type.unionId, narrowed, e.loc);
7310
7589
  if (helper) {
7311
- return ensureString(lowerer, { kind: "call", callee: helper, args: [e], type: narrowed, loc: e.loc }, node);
7590
+ return ensureString(lowerer, lowerer.checkedNarrowCall(helper, e, narrowed, e.loc), node);
7312
7591
  }
7313
7592
  }
7314
7593
  if (narrowed?.kind === "union" &&
@@ -7581,10 +7860,20 @@ export function lowerAsExpression(lowerer, expr) {
7581
7860
  if (target && target.kind !== "union" && !typeEquals(target, inner.type)) {
7582
7861
  const helper = lowerer.narrowedArmHelper(inner.type.unionId, target, locOf(expr));
7583
7862
  if (helper) {
7584
- return { kind: "call", callee: helper, args: [inner], type: target, loc: locOf(expr) };
7863
+ return lowerer.checkedNarrowCall(helper, inner, target, locOf(expr));
7585
7864
  }
7586
7865
  }
7587
7866
  }
7867
+ // `node.parent as Sub | undefined`: a union target whose class arm is
7868
+ // narrower than the stored class gets the same checked class view as
7869
+ // `node.parent as Sub`; the other arms keep their identical tags.
7870
+ if (target?.kind === "union" &&
7871
+ (inner.type.kind === "union" || inner.type.kind === "object") &&
7872
+ !typeEquals(target, inner.type)) {
7873
+ const asserted = checkedClassUnionAssertion(lowerer, inner, target, locOf(expr));
7874
+ if (asserted)
7875
+ return asserted;
7876
+ }
7588
7877
  return inner; // erasure, unchanged
7589
7878
  }
7590
7879
  if (inner.type.kind === "jsval") {
@@ -7711,7 +8000,7 @@ export function lowerPrefixUnary(lowerer, expr) {
7711
8000
  }
7712
8001
  case ts.SyntaxKind.ExclamationToken: {
7713
8002
  // `!x` is ToBoolean-then-negate: f64/string operands go through toBool.
7714
- const operand = lowerer.ensureBool(lowerer.lowerExpr(expr.operand), expr.operand);
8003
+ const operand = lowerer.ensureBool(deferredSlotOr(lowerer, runtimeOptionalStorageOperand(lowerer, expr.operand) ?? lowerer.lowerExpr(expr.operand)), expr.operand);
7715
8004
  return { kind: "unary", op: "!", operand, type: BOOL, loc };
7716
8005
  }
7717
8006
  case ts.SyntaxKind.TildeToken: {
@@ -7816,7 +8105,15 @@ export function lowerIncDec(lowerer, expr, prefix) {
7816
8105
  const type = raw.type;
7817
8106
  const read = type.kind === "array"
7818
8107
  ? arrayValueRead(lowerer, receiver, index, type.elem, loc)
7819
- : { kind: "bytesIntrinsic", method: "get", receiver, args: [index], type: F64, loc };
8108
+ : {
8109
+ kind: "bytesIntrinsic",
8110
+ method: "get",
8111
+ receiver,
8112
+ args: [index],
8113
+ type: F64,
8114
+ loc,
8115
+ invalidNaN: true,
8116
+ };
7820
8117
  return finish(read, (value) => type.kind === "array"
7821
8118
  ? arrayValueStore(lowerer, receiver, index, lowerer.coerceInto(access, value, type.elem), type.elem, loc)
7822
8119
  : {
@@ -7848,6 +8145,7 @@ export function lowerIncDec(lowerer, expr, prefix) {
7848
8145
  ? lowerer.fieldTarget(access)
7849
8146
  : symbolFieldTarget(lowerer, access);
7850
8147
  if (target && lowerer.dynConvertible(target.fieldType)) {
8148
+ checkDeferredMemberReceiver(lowerer, target, access);
7851
8149
  target.obj = save(target.obj, "%incrementReceiver");
7852
8150
  return finish(lowerer.fieldGetExpr(target, loc, access), (value) => lowerer.fieldSetStmt(target, lowerer.coerceInto(access, value, target.fieldType), loc, access));
7853
8151
  }
@@ -8081,12 +8379,75 @@ export function lowerCompoundValueToTarget(lowerer, expr, compound, target) {
8081
8379
  }
8082
8380
  lowerer.unsupported("SC1043", expr);
8083
8381
  }
8382
+ /** Equality of two NaN-coded values (nan-coded-reads.ts), each of which may
8383
+ * stand for undefined and never holds a genuine NaN: Node's undefined equals
8384
+ * undefined, so two NaNs compare equal here. Operands evaluate once, in
8385
+ * order. */
8386
+ function lowerNanCodedEquality(lowerer, expr) {
8387
+ const loc = locOf(expr);
8388
+ const left = lowerer.lowerExpr(expr.left);
8389
+ const right = lowerer.lowerExpr(expr.right);
8390
+ if (left.type.kind !== "f64" || right.type.kind !== "f64") {
8391
+ throw new InternalCompilerError("NaN-coded equality operand is not a plain number");
8392
+ }
8393
+ const stmts = [];
8394
+ const stable = (value, name) => {
8395
+ if (value.kind === "varRef" || value.kind === "numLit")
8396
+ return value;
8397
+ const tmp = lowerer.declareHiddenLocal(name, F64);
8398
+ stmts.push({ kind: "varDecl", localId: tmp.id, init: value, loc });
8399
+ return varRef(tmp.id, F64, loc);
8400
+ };
8401
+ const a = stable(left, "%eqLeft");
8402
+ const b = stable(right, "%eqRight");
8403
+ const isNaN = (value) => ({
8404
+ kind: "libCall",
8405
+ fn: "num.isNaN",
8406
+ args: [value],
8407
+ type: BOOL,
8408
+ loc,
8409
+ });
8410
+ const bothUndefined = {
8411
+ kind: "logical",
8412
+ op: "&&",
8413
+ left: isNaN(a),
8414
+ right: isNaN(b),
8415
+ type: BOOL,
8416
+ loc,
8417
+ };
8418
+ const op = expr.operatorToken.kind;
8419
+ const negated = op === ts.SyntaxKind.ExclamationEqualsEqualsToken ||
8420
+ op === ts.SyntaxKind.ExclamationEqualsToken;
8421
+ const result = negated
8422
+ ? {
8423
+ kind: "logical",
8424
+ op: "&&",
8425
+ left: { kind: "bin", op: "!==", left: a, right: b, type: BOOL, loc },
8426
+ right: { kind: "unary", op: "!", operand: bothUndefined, type: BOOL, loc },
8427
+ type: BOOL,
8428
+ loc,
8429
+ }
8430
+ : {
8431
+ kind: "logical",
8432
+ op: "||",
8433
+ left: { kind: "bin", op: "===", left: a, right: b, type: BOOL, loc },
8434
+ right: bothUndefined,
8435
+ type: BOOL,
8436
+ loc,
8437
+ };
8438
+ return stmts.length === 0 ? result : { kind: "seqExpr", stmts, result, type: BOOL, loc };
8439
+ }
8084
8440
  export function lowerBinary(lowerer, expr) {
8085
8441
  const loc = locOf(expr);
8086
8442
  const op = expr.operatorToken.kind;
8087
8443
  const cacheHas = lowerRequireCacheHas(lowerer, expr);
8088
8444
  if (cacheHas)
8089
8445
  return cacheHas;
8446
+ if (lowerer.nanCodedReads?.needsUndefinedEquality(expr)) {
8447
+ const undefinedEquality = lowerNanCodedEquality(lowerer, expr);
8448
+ if (undefinedEquality)
8449
+ return undefinedEquality;
8450
+ }
8090
8451
  if (op === ts.SyntaxKind.EqualsToken ||
8091
8452
  (op >= ts.SyntaxKind.FirstCompoundAssignment && op <= ts.SyntaxKind.LastCompoundAssignment)) {
8092
8453
  const urlWrite = lowerUrlAssignment(lowerer, expr);
@@ -8362,7 +8723,7 @@ export function lowerBinary(lowerer, expr) {
8362
8723
  const nullTest = lowerLooseNullCompare(lowerer, expr, loc);
8363
8724
  if (nullTest)
8364
8725
  return nullTest;
8365
- const loose = lowerAbstractEquality(lowerer, lowerer.lowerExpr(expr.left), lowerer.lowerExpr(expr.right), op === ts.SyntaxKind.ExclamationEqualsToken, loc);
8726
+ const loose = lowerAbstractEquality(lowerer, deferredSlotOr(lowerer, lowerer.lowerExpr(expr.left)), deferredSlotOr(lowerer, lowerer.lowerExpr(expr.right)), op === ts.SyntaxKind.ExclamationEqualsToken, loc);
8366
8727
  if (loose)
8367
8728
  return loose;
8368
8729
  lowerer.unsupported("SC1040", expr, undefined, "object-to-primitive loose equality can call user-defined valueOf/toString methods — compare explicit primitive conversions instead");
@@ -8409,12 +8770,26 @@ export function lowerBinary(lowerer, expr) {
8409
8770
  }
8410
8771
  const strictEquality = op === ts.SyntaxKind.EqualsEqualsEqualsToken ||
8411
8772
  op === ts.SyntaxKind.ExclamationEqualsEqualsToken;
8773
+ // An identifier whose storage is runtime-optional is compared by its
8774
+ // stored value: the checker's narrowing to the present arm is not a
8775
+ // runtime proof. Identifier reads are pure, so taking the stored value
8776
+ // after both operands lowered keeps the evaluation order. A union on
8777
+ // the other side keeps the narrowed read (union-to-union comparison
8778
+ // has no lowering).
8412
8779
  let left = strictEquality
8413
8780
  ? (lowerAbsenceProbe(lowerer, expr.left) ?? lowerer.lowerExpr(expr.left))
8414
8781
  : lowerer.lowerExpr(expr.left);
8415
8782
  let right = strictEquality
8416
8783
  ? (lowerAbsenceProbe(lowerer, expr.right) ?? lowerer.lowerExpr(expr.right))
8417
8784
  : lowerer.lowerExpr(expr.right);
8785
+ if (strictEquality) {
8786
+ const storedLeft = runtimeOptionalStorageOperand(lowerer, expr.left);
8787
+ const storedRight = runtimeOptionalStorageOperand(lowerer, expr.right);
8788
+ if (storedLeft !== null && right.type.kind !== "union")
8789
+ left = storedLeft;
8790
+ if (storedRight !== null && left.type.kind !== "union")
8791
+ right = storedRight;
8792
+ }
8418
8793
  if (strictEquality && (left.type.kind === "caught" || right.type.kind === "caught")) {
8419
8794
  if (left.type.kind === "caught")
8420
8795
  left = { kind: "caughtToDyn", value: left, type: DYN, loc: left.loc };
@@ -9266,7 +9641,9 @@ function lowerLogicalChain(lowerer, expr) {
9266
9641
  current = left;
9267
9642
  continue;
9268
9643
  }
9269
- result = lowerLogicalPair(lowerer, current, lowerAbsenceProbe(lowerer, left) ?? lowerer.lowerExpr(left));
9644
+ result = lowerLogicalPair(lowerer, current, current.operatorToken.kind === ts.SyntaxKind.BarBarToken
9645
+ ? lowerPresenceOperand(lowerer, left)
9646
+ : (lowerAbsenceProbe(lowerer, left) ?? lowerer.lowerExpr(left)));
9270
9647
  break;
9271
9648
  }
9272
9649
  for (let i = parents.length - 1; i >= 0; i--) {
@@ -9921,11 +10298,12 @@ function lowerUnionTypeofTest(lowerer, expr, loc) {
9921
10298
  for (const [a, b] of operandPairs(expr)) {
9922
10299
  if (!ts.isTypeOfExpression(a))
9923
10300
  continue;
9924
- if (lowerer.mapTypeOf(lowerer.typeOf(a.expression))?.kind !== "union")
10301
+ const stored = runtimeOptionalStorageOperand(lowerer, a.expression);
10302
+ if (stored === null && lowerer.mapTypeOf(lowerer.typeOf(a.expression))?.kind !== "union")
9925
10303
  continue;
9926
10304
  if (!ts.isStringLiteral(b))
9927
10305
  continue; // bare-typeof + strEq handles pure operands
9928
- const value = lowerer.lowerExpr(a.expression);
10306
+ const value = stored ?? lowerer.lowerExpr(a.expression);
9929
10307
  if (value.type.kind !== "union")
9930
10308
  continue; // defensive: an already-narrowed use
9931
10309
  const unionId = value.type.unionId;
@@ -12012,6 +12390,11 @@ export function lowerUnionProperty(lowerer, expr) {
12012
12390
  const helper = lowerer.narrowedRetagHelper(expr.expression, value.type.unionId, receiverIr.unionId, locOf(expr));
12013
12391
  if (helper)
12014
12392
  value = { kind: "call", callee: helper, args: [value], type: receiverIr, loc: locOf(expr) };
12393
+ // Optional storage of a base class (a runtime-optional binding holding
12394
+ // `Base | undefined`) that `instanceof` narrowed to several subclasses:
12395
+ // extract the instance and test its class, as typed slots do.
12396
+ else
12397
+ value = narrowStoredClassValue(lowerer, value, receiverIr) ?? value;
12015
12398
  }
12016
12399
  // A checker-union receiver whose VALUE lowered to a plain RECORD (the
12017
12400
  // merged-signature fiction — `runner(cmd, args)` where runner joined
@@ -12088,13 +12471,7 @@ export function lowerUnionProperty(lowerer, expr) {
12088
12471
  if (receiver === null) {
12089
12472
  const helper = lowerer.narrowedArmHelper(value.type.unionId, objectType, locOf(expr.expression));
12090
12473
  if (helper !== null)
12091
- receiver = {
12092
- kind: "call",
12093
- callee: helper,
12094
- args: [value],
12095
- type: objectType,
12096
- loc: locOf(expr.expression),
12097
- };
12474
+ receiver = lowerer.checkedNarrowCall(helper, value, objectType, locOf(expr.expression));
12098
12475
  }
12099
12476
  if (receiver !== null) {
12100
12477
  return {
@@ -12140,6 +12517,11 @@ export function lowerUnionProperty(lowerer, expr) {
12140
12517
  const keyed = lowerUnionKeyedRead(lowerer, expr, value.type.unionId, value, key, field);
12141
12518
  if (keyed)
12142
12519
  return keyed;
12520
+ // Class arms declaring the field with compatible but different types
12521
+ // (`T | undefined` beside `T`): per-arm slot reads widened to one type.
12522
+ const widened = lowerUnionFieldRead(lowerer, expr, value);
12523
+ if (widened)
12524
+ return widened;
12143
12525
  // JavaScript overloads commonly inspect a class brand on a scalar-or-
12144
12526
  // instance argument (e.g. Matrix4.makeTranslation). Preserve primitive
12145
12527
  // missing-property semantics and dispatch class data through its native
@@ -12304,15 +12686,14 @@ function classFieldTarget(lowerer, receiverNode, receiverType, fieldName, saved)
12304
12686
  const lowerObjectReceiver = () => {
12305
12687
  let obj = represented;
12306
12688
  if (obj.type.kind === "union") {
12689
+ // A receiver that may hold a missing value (a field assigned an
12690
+ // unchecked read): Node's member-read TypeError for the unit arm.
12691
+ const present = lowerer.runtimeOptionalPropertyReceiver(receiverNode, obj, receiverType, fieldName);
12692
+ if (present)
12693
+ return present;
12307
12694
  const helper = lowerer.narrowedArmHelper(obj.type.unionId, receiverType, locOf(receiverNode));
12308
12695
  obj = helper
12309
- ? {
12310
- kind: "call",
12311
- callee: helper,
12312
- args: [obj],
12313
- type: receiverType,
12314
- loc: locOf(receiverNode),
12315
- }
12696
+ ? lowerer.checkedNarrowCall(helper, obj, receiverType, locOf(receiverNode))
12316
12697
  : lowerer.maybeNarrow(obj, receiverNode);
12317
12698
  }
12318
12699
  return lowerer.coerceInto(receiverNode, obj, receiverType);
@@ -12476,13 +12857,7 @@ export function fieldTarget(lowerer, access) {
12476
12857
  ? lowerer.narrowedArmHelper(obj.type.unionId, present, locOf(access.expression))
12477
12858
  : null;
12478
12859
  obj = helper
12479
- ? {
12480
- kind: "call",
12481
- callee: helper,
12482
- args: [obj],
12483
- type: present,
12484
- loc: locOf(access.expression),
12485
- }
12860
+ ? lowerer.checkedNarrowCall(helper, obj, present, locOf(access.expression))
12486
12861
  : lowerer.maybeNarrow(obj, access.expression);
12487
12862
  }
12488
12863
  if (obj.type.kind !== "record")
@@ -12689,6 +13064,16 @@ function symbolFieldTarget(lowerer, expr) {
12689
13064
  * tsc-clean (the property types as the setter's param), but Node yields
12690
13065
  * undefined, which these property types cannot represent. */
12691
13066
  export function fieldGetExpr(lowerer, target, loc, blame) {
13067
+ // A member read through an unassigned deferred-init field throws Node's
13068
+ // member-read TypeError instead of the generic checked extraction.
13069
+ if (target.container === "class" &&
13070
+ ts.isPropertyAccessExpression(blame) &&
13071
+ target.obj.type.kind === "object" &&
13072
+ lowerer.deferredFieldSlot(target.obj) !== null) {
13073
+ const checked = lowerer.runtimeOptionalPropertyReceiver(blame.expression, target.obj, target.obj.type, target.field);
13074
+ if (checked)
13075
+ target = { ...target, obj: checked };
13076
+ }
12692
13077
  if (target.container === "dynamic")
12693
13078
  return lowerer.coerceInto(blame, {
12694
13079
  kind: "dynKeyGet",
@@ -12812,6 +13197,34 @@ export function fieldGetExpr(lowerer, target, loc, blame) {
12812
13197
  if (lowerer.classes.get(target.className)?.deferredInitFields?.has(target.field) === true &&
12813
13198
  target.fieldType.kind === "union") {
12814
13199
  const inner = lowerer.stripUndefinedArm(target.fieldType);
13200
+ // Reference arms over a stable receiver check inline: the present
13201
+ // arm is a plain projection of the slot, so ordinary reads keep their
13202
+ // borrowed form and only an unassigned slot reaches the throw.
13203
+ const unionId = target.fieldType.unionId;
13204
+ const presentTag = lowerer.armTag(unionId, inner);
13205
+ const undefTag = lowerer.armTag(unionId, UNDEFINED_T);
13206
+ if (inner.kind === "object" &&
13207
+ presentTag >= 0 &&
13208
+ undefTag >= 0 &&
13209
+ lowerer.unions.get(unionId)?.arms.length === 2 &&
13210
+ isSafeToRepeat(read)) {
13211
+ return {
13212
+ kind: "ternary",
13213
+ cond: {
13214
+ kind: "unionIsTag",
13215
+ unionId,
13216
+ tag: undefTag,
13217
+ negated: false,
13218
+ value: read,
13219
+ type: BOOL,
13220
+ loc,
13221
+ },
13222
+ then: nodeThrowExpr(1, "", DEFERRED_READ_MESSAGE, inner, loc),
13223
+ else_: { kind: "unionNarrow", unionId, tag: presentTag, value: read, type: inner, loc },
13224
+ type: inner,
13225
+ loc,
13226
+ };
13227
+ }
12815
13228
  const helper = lowerer.deferredReadHelper(target.fieldType.unionId, inner, loc);
12816
13229
  if (helper)
12817
13230
  return { kind: "call", callee: helper, args: [read], type: inner, loc };
@@ -12831,6 +13244,75 @@ export function fieldGetExpr(lowerer, target, loc, blame) {
12831
13244
  * call). A write to a getter-only property never gets here in a clean
12832
13245
  * program (tsc's TS2540 is the fence); the rejection is the backstop. */
12833
13246
  export function fieldSetStmt(lowerer, target, value, loc, blame) {
13247
+ // A member write through an unassigned deferred-init field: the value
13248
+ // still evaluates first, then the write throws Node's TypeError.
13249
+ const deferredSlot = target.container === "class" &&
13250
+ !((target.field === "message" || target.field === "name") &&
13251
+ (target.className === "%Error" || lowerer.isSubclassOf(target.className, "%Error")))
13252
+ ? lowerer.deferredFieldSlot(target.obj)
13253
+ : null;
13254
+ if (target.container === "class" && deferredSlot?.type.kind === "union") {
13255
+ const unionId = deferredSlot.type.unionId;
13256
+ const undefTag = lowerer.armTag(unionId, UNDEFINED_T);
13257
+ const presentTag = lowerer.armTag(unionId, target.obj.type);
13258
+ if (undefTag >= 0 && presentTag >= 0) {
13259
+ // A value that cannot write anything leaves the field unchanged, so
13260
+ // the field is read after it (no snapshot of the slot).
13261
+ const late = isSafeToRepeat(deferredSlot) && writeFree(value);
13262
+ const receiver = late
13263
+ ? null
13264
+ : lowerer.declareHiddenLocal("%deferredWriteObject", deferredSlot.type);
13265
+ const stored = lowerer.declareHiddenLocal("%deferredWriteValue", value.type);
13266
+ const receiverRef = receiver ? varRef(receiver.id, receiver.type, loc) : deferredSlot;
13267
+ const result = varRef(stored.id, stored.type, loc);
13268
+ const write = {
13269
+ kind: "fieldSet",
13270
+ obj: {
13271
+ kind: "unionNarrow",
13272
+ unionId,
13273
+ tag: presentTag,
13274
+ value: receiverRef,
13275
+ type: target.obj.type,
13276
+ loc,
13277
+ },
13278
+ className: target.className,
13279
+ field: target.field,
13280
+ value: result,
13281
+ loc,
13282
+ };
13283
+ return {
13284
+ kind: "exprStmt",
13285
+ expr: {
13286
+ kind: "seqExpr",
13287
+ stmts: [
13288
+ ...(receiver
13289
+ ? [{ kind: "varDecl", localId: receiver.id, init: deferredSlot, loc }]
13290
+ : []),
13291
+ { kind: "varDecl", localId: stored.id, init: value, loc },
13292
+ ],
13293
+ result: {
13294
+ kind: "ternary",
13295
+ cond: {
13296
+ kind: "unionIsTag",
13297
+ unionId,
13298
+ tag: undefTag,
13299
+ value: receiverRef,
13300
+ negated: false,
13301
+ type: BOOL,
13302
+ loc,
13303
+ },
13304
+ then: nodeThrowExpr(1, "", `Cannot set properties of undefined (setting '${target.field}')`, result.type, loc),
13305
+ else_: { kind: "seqExpr", stmts: [write], result, type: result.type, loc },
13306
+ type: result.type,
13307
+ loc,
13308
+ },
13309
+ type: result.type,
13310
+ loc,
13311
+ },
13312
+ loc,
13313
+ };
13314
+ }
13315
+ }
12834
13316
  if (target.container === "dynamic")
12835
13317
  return {
12836
13318
  kind: "exprStmt",
@@ -13148,6 +13630,7 @@ function lowerFieldCompoundValue(lowerer, access, op, rhsNode, loc) {
13148
13630
  const target = targetOf();
13149
13631
  if (!target)
13150
13632
  lowerer.unsupported("SC1090", access, "compound assignment to unsupported field targets");
13633
+ checkDeferredMemberReceiver(lowerer, target, access);
13151
13634
  target.obj = save(target.obj, "%compoundReceiver");
13152
13635
  // Accessors observe getter, RHS side effects, then setter, all through
13153
13636
  // the saved receiver.