@scriptc/compiler 0.2.6 → 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (368) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +5 -18
  2. package/dist/backend/cycle-analysis.d.ts +21 -9
  3. package/dist/backend/cycle-analysis.js +139 -67
  4. package/dist/backend/cycle-analysis.js.map +1 -1
  5. package/dist/backend/cycle-analysis.test.js +283 -3
  6. package/dist/backend/cycle-analysis.test.js.map +1 -1
  7. package/dist/backend/cycle-mutability.d.ts +39 -0
  8. package/dist/backend/cycle-mutability.js +205 -0
  9. package/dist/backend/cycle-mutability.js.map +1 -0
  10. package/dist/backend/link-plan-core.d.ts +2 -1
  11. package/dist/backend/link-plan-core.js +15 -3
  12. package/dist/backend/link-plan-core.js.map +1 -1
  13. package/dist/backend/link-plan.d.ts +2 -1
  14. package/dist/backend/link-plan.js.map +1 -1
  15. package/dist/backend/llvm/alloc.d.ts +40 -0
  16. package/dist/backend/llvm/alloc.js +205 -0
  17. package/dist/backend/llvm/alloc.js.map +1 -0
  18. package/dist/backend/llvm/alloc.test.d.ts +1 -0
  19. package/dist/backend/llvm/alloc.test.js +102 -0
  20. package/dist/backend/llvm/alloc.test.js.map +1 -0
  21. package/dist/backend/llvm/call-lifetimes.d.ts +15 -3
  22. package/dist/backend/llvm/call-lifetimes.js +42 -18
  23. package/dist/backend/llvm/call-lifetimes.js.map +1 -1
  24. package/dist/backend/llvm/call-lifetimes.test.js +170 -0
  25. package/dist/backend/llvm/call-lifetimes.test.js.map +1 -1
  26. package/dist/backend/llvm/classes.d.ts +4 -1
  27. package/dist/backend/llvm/classes.js +35 -32
  28. package/dist/backend/llvm/classes.js.map +1 -1
  29. package/dist/backend/llvm/classes.test.js +36 -3
  30. package/dist/backend/llvm/classes.test.js.map +1 -1
  31. package/dist/backend/llvm/common.d.ts +13 -0
  32. package/dist/backend/llvm/common.js +30 -0
  33. package/dist/backend/llvm/common.js.map +1 -1
  34. package/dist/backend/llvm/constant-callbacks.d.ts +19 -3
  35. package/dist/backend/llvm/constant-callbacks.js +289 -52
  36. package/dist/backend/llvm/constant-callbacks.js.map +1 -1
  37. package/dist/backend/llvm/constant-callbacks.test.js +140 -3
  38. package/dist/backend/llvm/constant-callbacks.test.js.map +1 -1
  39. package/dist/backend/llvm/dense-array-access.d.ts +29 -0
  40. package/dist/backend/llvm/dense-array-access.js +335 -0
  41. package/dist/backend/llvm/dense-array-access.js.map +1 -0
  42. package/dist/backend/llvm/dense-array-access.test.d.ts +1 -0
  43. package/dist/backend/llvm/dense-array-access.test.js +149 -0
  44. package/dist/backend/llvm/dense-array-access.test.js.map +1 -0
  45. package/dist/backend/llvm/dyn.d.ts +34 -0
  46. package/dist/backend/llvm/dyn.js +189 -1
  47. package/dist/backend/llvm/dyn.js.map +1 -1
  48. package/dist/backend/llvm/emitter.d.ts +124 -4
  49. package/dist/backend/llvm/emitter.js +623 -105
  50. package/dist/backend/llvm/emitter.js.map +1 -1
  51. package/dist/backend/llvm/emitter.test.js +68 -6
  52. package/dist/backend/llvm/emitter.test.js.map +1 -1
  53. package/dist/backend/llvm/expr-async.js +58 -4
  54. package/dist/backend/llvm/expr-async.js.map +1 -1
  55. package/dist/backend/llvm/expr-async.test.d.ts +1 -0
  56. package/dist/backend/llvm/expr-async.test.js +62 -0
  57. package/dist/backend/llvm/expr-async.test.js.map +1 -0
  58. package/dist/backend/llvm/expr-calls.js +64 -6
  59. package/dist/backend/llvm/expr-calls.js.map +1 -1
  60. package/dist/backend/llvm/expr-containers.js +16 -5
  61. package/dist/backend/llvm/expr-containers.js.map +1 -1
  62. package/dist/backend/llvm/expr-control.js +92 -2
  63. package/dist/backend/llvm/expr-control.js.map +1 -1
  64. package/dist/backend/llvm/expr-dispatch.js +2 -0
  65. package/dist/backend/llvm/expr-dispatch.js.map +1 -1
  66. package/dist/backend/llvm/expr-dynamic.js +174 -25
  67. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  68. package/dist/backend/llvm/expr-primitives.d.ts +1 -1
  69. package/dist/backend/llvm/expr-primitives.js +52 -24
  70. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  71. package/dist/backend/llvm/expr-primitives.test.js +1 -1
  72. package/dist/backend/llvm/expr-records.js +3 -3
  73. package/dist/backend/llvm/expr-records.js.map +1 -1
  74. package/dist/backend/llvm/expr-stream-bridges.js +59 -2
  75. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  76. package/dist/backend/llvm/expr-stream-bridges.test.js +1 -1
  77. package/dist/backend/llvm/integer-remainder.d.ts +11 -0
  78. package/dist/backend/llvm/integer-remainder.js +91 -0
  79. package/dist/backend/llvm/integer-remainder.js.map +1 -1
  80. package/dist/backend/llvm/layouts.d.ts +2 -1
  81. package/dist/backend/llvm/layouts.js +3 -2
  82. package/dist/backend/llvm/layouts.js.map +1 -1
  83. package/dist/backend/llvm/lazy-captures.d.ts +16 -0
  84. package/dist/backend/llvm/lazy-captures.js +96 -0
  85. package/dist/backend/llvm/lazy-captures.js.map +1 -0
  86. package/dist/backend/llvm/lazy-captures.test.d.ts +1 -0
  87. package/dist/backend/llvm/lazy-captures.test.js +78 -0
  88. package/dist/backend/llvm/lazy-captures.test.js.map +1 -0
  89. package/dist/backend/llvm/lib-filesystem.js +3 -4
  90. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  91. package/dist/backend/llvm/local-array-reads.d.ts +5 -1
  92. package/dist/backend/llvm/local-array-reads.js +78 -17
  93. package/dist/backend/llvm/local-array-reads.js.map +1 -1
  94. package/dist/backend/llvm/local-array-reads.test.js +78 -1
  95. package/dist/backend/llvm/local-array-reads.test.js.map +1 -1
  96. package/dist/backend/llvm/local-union-storage.d.ts +5 -1
  97. package/dist/backend/llvm/local-union-storage.js +48 -6
  98. package/dist/backend/llvm/local-union-storage.js.map +1 -1
  99. package/dist/backend/llvm/local-union-storage.test.js +91 -4
  100. package/dist/backend/llvm/local-union-storage.test.js.map +1 -1
  101. package/dist/backend/llvm/map-read-lifetimes.test.js +1 -1
  102. package/dist/backend/llvm/nullable-fields.d.ts +28 -0
  103. package/dist/backend/llvm/nullable-fields.js +45 -0
  104. package/dist/backend/llvm/nullable-fields.js.map +1 -0
  105. package/dist/backend/llvm/nullable-fields.test.d.ts +1 -0
  106. package/dist/backend/llvm/nullable-fields.test.js +48 -0
  107. package/dist/backend/llvm/nullable-fields.test.js.map +1 -0
  108. package/dist/backend/llvm/serialized-ir-emission.test.d.ts +1 -0
  109. package/dist/backend/llvm/serialized-ir-emission.test.js +52 -0
  110. package/dist/backend/llvm/serialized-ir-emission.test.js.map +1 -0
  111. package/dist/backend/llvm/shapes.d.ts +69 -2
  112. package/dist/backend/llvm/shapes.js +259 -27
  113. package/dist/backend/llvm/shapes.js.map +1 -1
  114. package/dist/backend/llvm/shapes.test.js +114 -5
  115. package/dist/backend/llvm/shapes.test.js.map +1 -1
  116. package/dist/backend/llvm/stack-callbacks.js +2 -3
  117. package/dist/backend/llvm/stack-callbacks.js.map +1 -1
  118. package/dist/backend/llvm/stack-captures.d.ts +3 -1
  119. package/dist/backend/llvm/stack-captures.js +5 -3
  120. package/dist/backend/llvm/stack-captures.js.map +1 -1
  121. package/dist/backend/llvm/stack-unions.test.js +38 -1
  122. package/dist/backend/llvm/stack-unions.test.js.map +1 -1
  123. package/dist/backend/llvm/string-construction.test.js +1 -1
  124. package/dist/backend/llvm/string-key-hash.d.ts +8 -0
  125. package/dist/backend/llvm/string-key-hash.js +59 -0
  126. package/dist/backend/llvm/string-key-hash.js.map +1 -0
  127. package/dist/backend/llvm/string-key-hash.test.d.ts +1 -0
  128. package/dist/backend/llvm/string-key-hash.test.js +34 -0
  129. package/dist/backend/llvm/string-key-hash.test.js.map +1 -0
  130. package/dist/backend/llvm/string-lifetimes.test.js +41 -4
  131. package/dist/backend/llvm/string-lifetimes.test.js.map +1 -1
  132. package/dist/backend/llvm/switch-dispatch.js +1 -1
  133. package/dist/backend/llvm/switch-dispatch.js.map +1 -1
  134. package/dist/backend/llvm/switch-dispatch.test.js +2 -2
  135. package/dist/backend/llvm/switch-dispatch.test.js.map +1 -1
  136. package/dist/backend/may-throw.js +3 -0
  137. package/dist/backend/may-throw.js.map +1 -1
  138. package/dist/backend/may-throw.test.js +1 -1
  139. package/dist/backend/native/cache-warm.d.ts +2 -1
  140. package/dist/backend/native/cache-warm.js.map +1 -1
  141. package/dist/backend/native/contracts.d.ts +3 -2
  142. package/dist/backend/native/contracts.js.map +1 -1
  143. package/dist/backend/native/runtime-inputs.d.ts +1 -1
  144. package/dist/backend/native/runtime-inputs.js +1 -0
  145. package/dist/backend/native/runtime-inputs.js.map +1 -1
  146. package/dist/backend/native-codegen-core.d.ts +2 -1
  147. package/dist/backend/native-codegen-core.js.map +1 -1
  148. package/dist/backend/native-codegen.d.ts +5 -0
  149. package/dist/backend/native-codegen.js +4 -0
  150. package/dist/backend/native-codegen.js.map +1 -1
  151. package/dist/backend/native-codegen.test.js +23 -0
  152. package/dist/backend/native-codegen.test.js.map +1 -1
  153. package/dist/backend/native-link-info-core.d.ts +3 -2
  154. package/dist/backend/native-link-info-core.js.map +1 -1
  155. package/dist/backend/native-link-info.d.ts +2 -1
  156. package/dist/backend/native-link-info.js.map +1 -1
  157. package/dist/backend/native-link-info.test.js +2 -2
  158. package/dist/backend/native-link-info.test.js.map +1 -1
  159. package/dist/backend/native-tools.d.ts +3 -1
  160. package/dist/backend/native-tools.js +0 -1
  161. package/dist/backend/native-tools.js.map +1 -1
  162. package/dist/backend/optimization.d.ts +25 -0
  163. package/dist/backend/optimization.js +21 -0
  164. package/dist/backend/optimization.js.map +1 -0
  165. package/dist/backend/optimization.test.d.ts +1 -0
  166. package/dist/backend/optimization.test.js +24 -0
  167. package/dist/backend/optimization.test.js.map +1 -0
  168. package/dist/backend/runtime-abi.d.ts +2 -2
  169. package/dist/backend/runtime-abi.js +2 -2
  170. package/dist/backend/runtime-pack-core.d.ts +15 -4
  171. package/dist/backend/runtime-pack-core.js +23 -12
  172. package/dist/backend/runtime-pack-core.js.map +1 -1
  173. package/dist/backend/runtime-pack-native.d.ts +7 -3
  174. package/dist/backend/runtime-pack-native.js +0 -3
  175. package/dist/backend/runtime-pack-native.js.map +1 -1
  176. package/dist/backend/runtime-pack-targets.test.js +1 -1
  177. package/dist/backend/runtime-pack.d.ts +20 -2
  178. package/dist/backend/runtime-pack.js +23 -0
  179. package/dist/backend/runtime-pack.js.map +1 -1
  180. package/dist/backend/runtime-pack.test.js +115 -2
  181. package/dist/backend/runtime-pack.test.js.map +1 -1
  182. package/dist/backend/target-diagnostics.test.js +1 -1
  183. package/dist/backend/targets.d.ts +2 -1
  184. package/dist/backend/targets.js +1 -1
  185. package/dist/backend/targets.js.map +1 -1
  186. package/dist/cli/command.js +5 -4
  187. package/dist/cli/command.js.map +1 -1
  188. package/dist/cli/host.d.ts +2 -1
  189. package/dist/cli/usage.d.ts +1 -1
  190. package/dist/cli/usage.js +5 -2
  191. package/dist/cli/usage.js.map +1 -1
  192. package/dist/compile-types.d.ts +5 -2
  193. package/dist/diagnostics/diagnostic.js +10 -8
  194. package/dist/diagnostics/diagnostic.js.map +1 -1
  195. package/dist/executable/executable-cache.d.ts +2 -2
  196. package/dist/executable/executable-cache.js +7 -4
  197. package/dist/executable/executable-cache.js.map +1 -1
  198. package/dist/executable/executable-cache.test.js +20 -0
  199. package/dist/executable/executable-cache.test.js.map +1 -1
  200. package/dist/frontend/lowering/abstract-equality.js +5 -49
  201. package/dist/frontend/lowering/abstract-equality.js.map +1 -1
  202. package/dist/frontend/lowering/array-values.d.ts +23 -0
  203. package/dist/frontend/lowering/array-values.js +129 -0
  204. package/dist/frontend/lowering/array-values.js.map +1 -1
  205. package/dist/frontend/lowering/builtins/errors.js +17 -2
  206. package/dist/frontend/lowering/builtins/errors.js.map +1 -1
  207. package/dist/frontend/lowering/builtins/process.d.ts +6 -17
  208. package/dist/frontend/lowering/builtins/process.js +56 -29
  209. package/dist/frontend/lowering/builtins/process.js.map +1 -1
  210. package/dist/frontend/lowering/caught-value-dispatch.d.ts +11 -0
  211. package/dist/frontend/lowering/caught-value-dispatch.js +87 -0
  212. package/dist/frontend/lowering/caught-value-dispatch.js.map +1 -0
  213. package/dist/frontend/lowering/class-assertions.d.ts +4 -0
  214. package/dist/frontend/lowering/class-assertions.js +12 -4
  215. package/dist/frontend/lowering/class-assertions.js.map +1 -1
  216. package/dist/frontend/lowering/class-callbacks.d.ts +3 -3
  217. package/dist/frontend/lowering/class-callbacks.js +18 -5
  218. package/dist/frontend/lowering/class-callbacks.js.map +1 -1
  219. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +1 -0
  220. package/dist/frontend/lowering/class-dynamic-dispatch.js +4 -1
  221. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  222. package/dist/frontend/lowering/class-method-mutations.d.ts +5 -0
  223. package/dist/frontend/lowering/class-method-mutations.js +472 -0
  224. package/dist/frontend/lowering/class-method-mutations.js.map +1 -0
  225. package/dist/frontend/lowering/class-method-values.js +25 -5
  226. package/dist/frontend/lowering/class-method-values.js.map +1 -1
  227. package/dist/frontend/lowering/class-prototypes.js +8 -2
  228. package/dist/frontend/lowering/class-prototypes.js.map +1 -1
  229. package/dist/frontend/lowering/class-unions.d.ts +16 -0
  230. package/dist/frontend/lowering/class-unions.js +127 -0
  231. package/dist/frontend/lowering/class-unions.js.map +1 -0
  232. package/dist/frontend/lowering/coercions/builders.js +8 -1
  233. package/dist/frontend/lowering/coercions/builders.js.map +1 -1
  234. package/dist/frontend/lowering/coercions/function-adapters.js +2 -0
  235. package/dist/frontend/lowering/coercions/function-adapters.js.map +1 -1
  236. package/dist/frontend/lowering/coercions/identity.d.ts +7 -0
  237. package/dist/frontend/lowering/coercions/identity.js +26 -0
  238. package/dist/frontend/lowering/coercions/identity.js.map +1 -0
  239. package/dist/frontend/lowering/coercions/structural.js +9 -6
  240. package/dist/frontend/lowering/coercions/structural.js.map +1 -1
  241. package/dist/frontend/lowering/collection-narrowing.d.ts +6 -0
  242. package/dist/frontend/lowering/collection-narrowing.js +31 -0
  243. package/dist/frontend/lowering/collection-narrowing.js.map +1 -0
  244. package/dist/frontend/lowering/containers/array-callback-call.d.ts +7 -0
  245. package/dist/frontend/lowering/containers/array-callback-call.js +52 -0
  246. package/dist/frontend/lowering/containers/array-callback-call.js.map +1 -0
  247. package/dist/frontend/lowering/containers/array-callbacks.d.ts +1 -1
  248. package/dist/frontend/lowering/containers/array-callbacks.js +363 -49
  249. package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
  250. package/dist/frontend/lowering/containers/array-concat.d.ts +7 -0
  251. package/dist/frontend/lowering/containers/array-concat.js +130 -0
  252. package/dist/frontend/lowering/containers/array-concat.js.map +1 -0
  253. package/dist/frontend/lowering/containers/array-construction.d.ts +2 -0
  254. package/dist/frontend/lowering/containers/array-construction.js +95 -3
  255. package/dist/frontend/lowering/containers/array-construction.js.map +1 -1
  256. package/dist/frontend/lowering/containers/array-methods.d.ts +1 -11
  257. package/dist/frontend/lowering/containers/array-methods.js +43 -132
  258. package/dist/frontend/lowering/containers/array-methods.js.map +1 -1
  259. package/dist/frontend/lowering/containers/collection-methods.js +10 -1
  260. package/dist/frontend/lowering/containers/collection-methods.js.map +1 -1
  261. package/dist/frontend/lowering/containers/indexed-objects.js +56 -70
  262. package/dist/frontend/lowering/containers/indexed-objects.js.map +1 -1
  263. package/dist/frontend/lowering/cycle-initialization.d.ts +41 -0
  264. package/dist/frontend/lowering/cycle-initialization.js +277 -0
  265. package/dist/frontend/lowering/cycle-initialization.js.map +1 -0
  266. package/dist/frontend/lowering/expressions/evaluation-safety.js +4 -0
  267. package/dist/frontend/lowering/expressions/evaluation-safety.js.map +1 -1
  268. package/dist/frontend/lowering/expressions/object-literals.js +138 -32
  269. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  270. package/dist/frontend/lowering/expressions/union-field-write.d.ts +4 -4
  271. package/dist/frontend/lowering/expressions/union-field-write.js +54 -44
  272. package/dist/frontend/lowering/expressions/union-field-write.js.map +1 -1
  273. package/dist/frontend/lowering/iterator-adapters.d.ts +20 -0
  274. package/dist/frontend/lowering/iterator-adapters.js +605 -0
  275. package/dist/frontend/lowering/iterator-adapters.js.map +1 -0
  276. package/dist/frontend/lowering/lower-array-sort.d.ts +1 -1
  277. package/dist/frontend/lowering/lower-array-sort.js +44 -5
  278. package/dist/frontend/lowering/lower-array-sort.js.map +1 -1
  279. package/dist/frontend/lowering/lower-array-sort.test.d.ts +1 -0
  280. package/dist/frontend/lowering/lower-array-sort.test.js +31 -0
  281. package/dist/frontend/lowering/lower-array-sort.test.js.map +1 -0
  282. package/dist/frontend/lowering/lower-assert.js +7 -0
  283. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  284. package/dist/frontend/lowering/lower-builtin-values.js +1 -0
  285. package/dist/frontend/lowering/lower-builtin-values.js.map +1 -1
  286. package/dist/frontend/lowering/lower-calls.d.ts +3 -3
  287. package/dist/frontend/lowering/lower-calls.js +162 -121
  288. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  289. package/dist/frontend/lowering/lower-classes.d.ts +2 -0
  290. package/dist/frontend/lowering/lower-classes.js +45 -43
  291. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  292. package/dist/frontend/lowering/lower-exprs.d.ts +9 -2
  293. package/dist/frontend/lowering/lower-exprs.js +390 -157
  294. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  295. package/dist/frontend/lowering/lower-functions.js +32 -19
  296. package/dist/frontend/lowering/lower-functions.js.map +1 -1
  297. package/dist/frontend/lowering/lower-inspect.js +26 -2
  298. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  299. package/dist/frontend/lowering/lower-modules.js +10 -2
  300. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  301. package/dist/frontend/lowering/lower-stmts.js +46 -58
  302. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  303. package/dist/frontend/lowering/lowerer.d.ts +37 -0
  304. package/dist/frontend/lowering/lowerer.js +283 -18
  305. package/dist/frontend/lowering/lowerer.js.map +1 -1
  306. package/dist/frontend/lowering/native-ffi.js +3 -1
  307. package/dist/frontend/lowering/native-ffi.js.map +1 -1
  308. package/dist/frontend/lowering/runtime-optional-provenance.d.ts +15 -0
  309. package/dist/frontend/lowering/runtime-optional-provenance.js +40 -0
  310. package/dist/frontend/lowering/runtime-optional-provenance.js.map +1 -0
  311. package/dist/frontend/lowering/sanitize-class-types.test.js +2 -2
  312. package/dist/frontend/lowering/strict-equality.d.ts +9 -0
  313. package/dist/frontend/lowering/strict-equality.js +116 -0
  314. package/dist/frontend/lowering/strict-equality.js.map +1 -0
  315. package/dist/frontend/lowering/surfaces.js +3 -0
  316. package/dist/frontend/lowering/surfaces.js.map +1 -1
  317. package/dist/frontend/lowering/union-comparison.d.ts +5 -0
  318. package/dist/frontend/lowering/union-comparison.js +47 -0
  319. package/dist/frontend/lowering/union-comparison.js.map +1 -0
  320. package/dist/frontend/program.d.ts +38 -2
  321. package/dist/frontend/program.js +440 -59
  322. package/dist/frontend/program.js.map +1 -1
  323. package/dist/frontend/program.test.js +59 -6
  324. package/dist/frontend/program.test.js.map +1 -1
  325. package/dist/frontend/type-mapper.d.ts +1 -1
  326. package/dist/frontend/type-mapper.js +89 -14
  327. package/dist/frontend/type-mapper.js.map +1 -1
  328. package/dist/frontend/type-mapper.test.js +15 -3
  329. package/dist/frontend/type-mapper.test.js.map +1 -1
  330. package/dist/index.js +25 -9
  331. package/dist/index.js.map +1 -1
  332. package/dist/ir/analysis.d.ts +3 -1
  333. package/dist/ir/analysis.js +4 -0
  334. package/dist/ir/analysis.js.map +1 -1
  335. package/dist/ir/builtin-signatures.js +2 -3
  336. package/dist/ir/builtin-signatures.js.map +1 -1
  337. package/dist/ir/constant-tables.test.js +1 -1
  338. package/dist/ir/initializer-bindings.test.js +1 -1
  339. package/dist/ir/ir.d.ts +78 -15
  340. package/dist/ir/ir.js +20 -6
  341. package/dist/ir/ir.js.map +1 -1
  342. package/dist/ir/scalar-records.test.js +1 -1
  343. package/dist/ir/serialize.d.ts +1 -1
  344. package/dist/ir/serialize.js +3 -3
  345. package/dist/ir/serialize.js.map +1 -1
  346. package/dist/ir/traverse.js +8 -0
  347. package/dist/ir/traverse.js.map +1 -1
  348. package/dist/ir/validate.js +118 -20
  349. package/dist/ir/validate.js.map +1 -1
  350. package/dist/ir/validate.test.js +269 -8
  351. package/dist/ir/validate.test.js.map +1 -1
  352. package/dist/library/fence-eval.test.js +1 -1
  353. package/dist/library/int-infer.test.js +4 -4
  354. package/dist/library/library-cache.test.js +5 -5
  355. package/dist/library/library-profile.d.ts +2 -1
  356. package/dist/library/library-profile.js +4 -3
  357. package/dist/library/library-profile.js.map +1 -1
  358. package/dist/native/compiler.js.map +1 -1
  359. package/dist/native/compiler.test.js +2 -2
  360. package/dist/native/library.d.ts +2 -1
  361. package/dist/native/library.js.map +1 -1
  362. package/dist/native/prepare.js +27 -3
  363. package/dist/native/prepare.js.map +1 -1
  364. package/dist/native/sanitizer.d.ts +3 -2
  365. package/dist/native/sanitizer.js +3 -13
  366. package/dist/native/sanitizer.js.map +1 -1
  367. package/package.json +20 -20
  368. package/surface-manifest.json +8 -2
@@ -1,5 +1,8 @@
1
+ import { generatorDrain } from "./iterator-adapters.js";
2
+ import { lowerUnionEquality, tagEqualityMayMissAlias } from "./strict-equality.js";
3
+ import { isOptionalProcessStreamProperty } from "./builtins/process.js";
1
4
  import { lowerWorkerMetadata } from "./builtins/workers.js";
2
- import { dynUndefinedExpr, nodeThrowExpr, countedFor, numLit, strLit, varRef, } from "../../ir/build.js";
5
+ import { dynUndefinedExpr, nodeThrowExpr, numLit, strLit, varRef } from "../../ir/build.js";
3
6
  import { InternalCompilerError } from "../../errors.js";
4
7
  import { SYMBOL_T } from "../../ir/ir.js";
5
8
  import { literalValues } from "../literal-values.js";
@@ -11,9 +14,12 @@ import { literalUnionArm } from "../union-discriminants.js";
11
14
  * ToBoolean/ToString coercion helpers, and field/element reads and writes
12
15
  * (FieldTarget). */
13
16
  import * as ts from "../ts7/adapter.js";
17
+ import { constituentTypes } from "../ts7/checker.js";
14
18
  import { dirname } from "node:path";
15
19
  import * as posix from "node:path/posix";
16
20
  import { checkedClassAssertion } from "./class-assertions.js";
21
+ import { narrowClassUnion, narrowStoredClassValue } from "./class-unions.js";
22
+ import { lowerUnionFieldWrite } from "./expressions/union-field-write.js";
17
23
  import { captureContextArguments } from "./function-context.js";
18
24
  import { OBJECT_CALLABLE_VALUES } from "./surfaces.js";
19
25
  import { wasiGuestPath } from "../../wasi-paths.js";
@@ -23,9 +29,8 @@ import { ARRAY_METHODS, builtinConstLit, builtinFenceHintOf, builtinModuleConstO
23
29
  import { UNSUPPORTED, blockedBindingUseDiag, requiresDynamicPackageDiag, unsupportedDiag, } from "../../diagnostics/diagnostic.js";
24
30
  import { PoisonError, dynFallbackType, jsFuncNameOf, neverTaintedJsType, own } from "./lowerer.js";
25
31
  import { lowerCollectionSpread } from "./containers/collection-methods.js";
26
- import { lowerNpmStaticSafeIndexRead, lowerSafeIndexRead, tryLowerNumericIndexRead, } from "./containers/array-methods.js";
32
+ import { arrayValueRead, arrayValueStore, arrayValueType, lowerSafeIndexRead, tryLowerIndexTruthiness, tryLowerNumericIndexRead, } from "./array-values.js";
27
33
  import { strCharsCall } from "./containers/array-construction.js";
28
- import { arrayValueRead, arrayValueStore, arrayValueType } from "./array-values.js";
29
34
  import { lowerOptionalStringIndex } from "./string-index.js";
30
35
  import { tryLowerIndexedComparison } from "./indexed-comparison.js";
31
36
  import { npmStaticPackageOfPath } from "../npm-static.js";
@@ -98,8 +103,8 @@ export function templateRawTextOf(node) {
98
103
  const LOWER_EXPR_MAX_DEPTH = 200;
99
104
  let lowerExprDepth = 0;
100
105
  /** True when a property access names an ABSTRACT property declaration
101
- * (`abstract p: number` — a PropertyDeclaration, not an accessor): the
102
- * named-fence test for reads/writes through abstract-typed receivers. */
106
+ * (`abstract p: number` — a PropertyDeclaration, not an accessor).
107
+ * These uses need concrete property dispatch because the base has no slot. */
103
108
  export function abstractPropertyDeclOf(lowerer, expr) {
104
109
  const sym = lowerer.checker.getSymbolAtLocation(expr.name);
105
110
  if (!sym)
@@ -161,7 +166,10 @@ export function lowerExpr(lowerer, expr) {
161
166
  }
162
167
  lowerExprDepth++;
163
168
  try {
164
- return lowerExprInner(lowerer, expr);
169
+ const lowered = lowerExprInner(lowerer, expr);
170
+ if (lowered.type.kind === "void" && (lowerer.typeOf(expr).flags & ts.TypeFlags.Never) !== 0)
171
+ lowerer.neverValued.add(lowered);
172
+ return lowered;
165
173
  }
166
174
  finally {
167
175
  lowerExprDepth--;
@@ -288,6 +296,11 @@ function lowerExprInner(lowerer, expr) {
288
296
  if (ts.isNonNullExpression(expr)) {
289
297
  const inner = lowerer.lowerExpr(expr.expression);
290
298
  if (inner.type.kind === "union") {
299
+ // `!` performs no runtime check: a missing array element stays
300
+ // undefined where its destination can hold it.
301
+ if (ts.isElementAccessExpression(expr.expression) &&
302
+ assertedElementKeepsUndefined(lowerer, expr))
303
+ return inner;
291
304
  const use = runtimeOptionalUseOf(expr);
292
305
  if (runtimeOptionalAssertionErases(lowerer, expr, inner, use))
293
306
  return inner;
@@ -3075,6 +3088,11 @@ export function maybeNarrow(lowerer, expr, node) {
3075
3088
  // same trust-the-checker contract as the union bridge below.
3076
3089
  if (expr.type.kind === "object") {
3077
3090
  const narrowed = lowerer.mapTypeOf(lowerer.typeOf(node));
3091
+ if (narrowed?.kind === "union") {
3092
+ const union = narrowClassUnion(lowerer, expr, narrowed);
3093
+ if (union)
3094
+ return union;
3095
+ }
3078
3096
  if (narrowed?.kind === "object" &&
3079
3097
  narrowed.className !== expr.type.className &&
3080
3098
  lowerer.isSubclassOf(narrowed.className, expr.type.className)) {
@@ -3084,6 +3102,8 @@ export function maybeNarrow(lowerer, expr, node) {
3084
3102
  }
3085
3103
  if (expr.type.kind !== "union")
3086
3104
  return expr;
3105
+ if (ts.isPropertyAccessExpression(node) && isOptionalProcessStreamProperty(lowerer, node))
3106
+ return expr;
3087
3107
  // Represented fields and index values can include undefined even when
3088
3108
  // checker inference or lib.d.ts declares strings (RegExp captures).
3089
3109
  // Only a declaration that represents the optional arm can provide a
@@ -3228,6 +3248,9 @@ function runtimeOptionalReceiverRead(lowerer, expr, local, property, loc) {
3228
3248
  lowerer.unsupported("SC1090", expr, "a runtime-optional capture whose narrowed value type is not representable");
3229
3249
  }
3230
3250
  if (narrowed.kind === "union") {
3251
+ const classView = narrowStoredClassValue(lowerer, varRef(local.id, local.type, loc), narrowed);
3252
+ if (classView)
3253
+ return classView;
3231
3254
  // The checker may keep the receiver at the storage union unchanged
3232
3255
  // (`string | undefined` on a JS `.match()` call). There is no
3233
3256
  // sub-union to re-tag: preserve the value for the downstream
@@ -3254,6 +3277,13 @@ function runtimeOptionalReceiverRead(lowerer, expr, local, property, loc) {
3254
3277
  loc,
3255
3278
  };
3256
3279
  }
3280
+ if (narrowed.kind === "object") {
3281
+ const view = checkedClassAssertion(lowerer, varRef(local.id, local.type, loc), narrowed, loc);
3282
+ // Preserve the member-specific missing-value error on the two-arm
3283
+ // path below; mixed storage also needs to validate its concrete class.
3284
+ if (view && (lowerer.unions.get(local.type.unionId)?.arms.length ?? 0) > 2)
3285
+ return view;
3286
+ }
3257
3287
  const undefTag = lowerer.armTag(local.type.unionId, UNDEFINED_T);
3258
3288
  const def = lowerer.unions.get(local.type.unionId);
3259
3289
  if (!def || undefTag < 0)
@@ -3408,6 +3438,45 @@ function runtimeOptionalElementKey(expr) {
3408
3438
  return expr.text;
3409
3439
  return null;
3410
3440
  }
3441
+ /** Whether `xs[i]!` lands where an absent element's undefined is
3442
+ * representable: array storage (a literal element, a push/unshift
3443
+ * argument, an element assignment — arrays record the undefined state),
3444
+ * an equality operand, or a slot whose contextual type admits undefined.
3445
+ * TypeScript's `!` has no runtime effect, so such reads stay optional. */
3446
+ function assertedElementKeepsUndefined(lowerer, node) {
3447
+ let outer = node;
3448
+ while (ts.isParenthesizedExpression(outer.parent))
3449
+ outer = outer.parent;
3450
+ const parent = outer.parent;
3451
+ if (ts.isArrayLiteralExpression(parent))
3452
+ return true;
3453
+ // An equality test observes the missing element itself.
3454
+ if (ts.isBinaryExpression(parent) &&
3455
+ (parent.operatorToken.kind === ts.SyntaxKind.EqualsEqualsEqualsToken ||
3456
+ parent.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken ||
3457
+ parent.operatorToken.kind === ts.SyntaxKind.EqualsEqualsToken ||
3458
+ parent.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsToken))
3459
+ return true;
3460
+ const isArray = (receiver) => lowerer.checker.isArrayType(lowerer.typeOf(receiver));
3461
+ if (ts.isCallExpression(parent) &&
3462
+ parent.arguments.includes(outer) &&
3463
+ ts.isPropertyAccessExpression(parent.expression) &&
3464
+ (parent.expression.name.text === "push" || parent.expression.name.text === "unshift") &&
3465
+ isArray(parent.expression.expression))
3466
+ return true;
3467
+ if (ts.isBinaryExpression(parent) &&
3468
+ parent.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
3469
+ parent.right === outer &&
3470
+ ts.isElementAccessExpression(parent.left) &&
3471
+ isArray(parent.left.expression))
3472
+ return true;
3473
+ const contextual = lowerer.checker.getContextualType(outer);
3474
+ if (!contextual)
3475
+ return false;
3476
+ const admits = (type) => (type.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown | ts.TypeFlags.Undefined)) !== 0;
3477
+ return (admits(contextual) ||
3478
+ ((contextual.flags & ts.TypeFlags.Union) !== 0 && constituentTypes(contextual).some(admits)));
3479
+ }
3411
3480
  function runtimeOptionalAssertionErases(lowerer, expr, inner, use) {
3412
3481
  if (inner.type.kind !== "union" ||
3413
3482
  !use?.optional ||
@@ -3655,6 +3724,32 @@ export function lowerNullishCoalesce(lowerer, expr, loc) {
3655
3724
  }
3656
3725
  return result;
3657
3726
  }
3727
+ /** A plain value read that may be runtime-optional: an unchecked element
3728
+ * read, or a binding, member or call that carries one. Lowering these
3729
+ * without a destination type is the same as lowering them into one. */
3730
+ function isPlainValueRead(node) {
3731
+ while (ts.isParenthesizedExpression(node))
3732
+ node = node.expression;
3733
+ return (ts.isElementAccessExpression(node) ||
3734
+ ts.isIdentifier(node) ||
3735
+ ts.isPropertyAccessExpression(node) ||
3736
+ ts.isCallExpression(node));
3737
+ }
3738
+ /** A member access or call receiver needs the present value itself (JS
3739
+ * throws a TypeError reading a member of undefined). */
3740
+ function isMemberReceiver(node) {
3741
+ let child = node;
3742
+ let parent = node.parent;
3743
+ while (ts.isParenthesizedExpression(parent)) {
3744
+ child = parent;
3745
+ parent = parent.parent;
3746
+ }
3747
+ return (((ts.isPropertyAccessExpression(parent) ||
3748
+ ts.isElementAccessExpression(parent) ||
3749
+ ts.isCallExpression(parent)) &&
3750
+ parent.expression === child) ||
3751
+ (ts.isTaggedTemplateExpression(parent) && parent.tag === child));
3752
+ }
3658
3753
  function lowerNullishPair(lowerer, expr, loc, left) {
3659
3754
  if (left.type.kind === "dyn") {
3660
3755
  // `a ?? b` on a CHECKED-DYNAMIC left: the deciding test is the
@@ -3691,7 +3786,24 @@ function lowerNullishPair(lowerer, expr, loc, left) {
3691
3786
  const fresh = rest.length === 1 ? lowerer.emptyCollectionFor(expr.right, rest[0]) : null;
3692
3787
  if (fresh)
3693
3788
  return { kind: "nullish", left, right: fresh, type: fresh.type, loc };
3694
- const type = lowerer.irTypeOf(expr);
3789
+ let type = lowerer.irTypeOf(expr);
3790
+ // A runtime-optional read can reach the default even when declarations
3791
+ // call the left side present. Preserve a differently typed primitive
3792
+ // fallback rather than checking it against that incomplete result type.
3793
+ const rightType = lowerer.mapTypeOf(lowerer.typeOf(expr.right));
3794
+ const primitive = (t) => t.kind === "f64" || t.kind === "string" || t.kind === "bool";
3795
+ if (rightType &&
3796
+ primitive(type) &&
3797
+ primitive(rightType) &&
3798
+ !typeEquals(type, rightType) &&
3799
+ rest.every(primitive)) {
3800
+ const arms = [...rest];
3801
+ if (!arms.some((arm) => typeEquals(arm, rightType)))
3802
+ arms.push(rightType);
3803
+ arms.sort((a, b) => (typeKey(a) < typeKey(b) ? -1 : 1));
3804
+ type = { kind: "union", unionId: lowerer.unions.intern(arms) };
3805
+ lowerer.runtimeOptionalArithmeticTypes.set(expr, type);
3806
+ }
3695
3807
  if (type.kind === "dyn" && lowerer.dynConvertible(left.type)) {
3696
3808
  return {
3697
3809
  kind: "nullish",
@@ -3701,6 +3813,27 @@ function lowerNullishPair(lowerer, expr, loc, left) {
3701
3813
  loc,
3702
3814
  };
3703
3815
  }
3816
+ // A runtime-optional default (`name ?? names[0]`): the checker types an
3817
+ // unchecked element read as the bare element type, but an out-of-range
3818
+ // read is undefined at runtime. When the default shares the left's
3819
+ // optional union, that union is the result, so the undefined state
3820
+ // reaches the consumer (an optional return or parameter takes it as its
3821
+ // undefined arm; a plain slot still extracts the element with its
3822
+ // checked narrow).
3823
+ if (rest.length === 1 &&
3824
+ typeEquals(type, rest[0]) &&
3825
+ isPlainValueRead(expr.right) &&
3826
+ !isMemberReceiver(expr)) {
3827
+ const raw = lowerer.lowerExpr(expr.right);
3828
+ if (typeEquals(raw.type, left.type))
3829
+ return { kind: "nullish", left, right: raw, type: left.type, loc };
3830
+ // `names[0] ?? undefined`: an explicit unit default stays the left's arm.
3831
+ if (isUnitType(raw.type) && lowerer.armTag(left.type.unionId, raw.type) >= 0) {
3832
+ const right = lowerer.coerceInto(expr.right, raw, left.type);
3833
+ return { kind: "nullish", left, right, type: left.type, loc };
3834
+ }
3835
+ return { kind: "nullish", left, right: lowerer.coerceInto(expr.right, raw, type), type, loc };
3836
+ }
3704
3837
  if (typeEquals(type, left.type) || (rest.length === 1 && typeEquals(type, rest[0]))) {
3705
3838
  const right = lowerer.lowerExprExpecting(expr.right, type);
3706
3839
  return { kind: "nullish", left, right, type, loc };
@@ -3824,7 +3957,8 @@ export function lowerCondition(lowerer, expr) {
3824
3957
  };
3825
3958
  }
3826
3959
  }
3827
- return lowerer.ensureBool(lowerAbsenceProbe(lowerer, expr) ?? lowerer.lowerExpr(expr), expr);
3960
+ const value = lowerAbsenceProbe(lowerer, expr) ?? lowerer.lowerExpr(expr);
3961
+ return (tryLowerIndexTruthiness(lowerer, value, expr, locOf(expr)) ?? lowerer.ensureBool(value, expr));
3828
3962
  }
3829
3963
  function lowerPromiseThenPresence(lowerer, access, result) {
3830
3964
  if (access.name.text !== "then")
@@ -5031,6 +5165,13 @@ export function lowerArrayLiteral(lowerer, expr, expected) {
5031
5165
  loc: locOf(el),
5032
5166
  };
5033
5167
  }
5168
+ // `[...it]` over a generator (or an iterator adapted into one):
5169
+ // drain it once, in order, into a fresh element array.
5170
+ if (src.type.kind === "generator") {
5171
+ const drained = generatorDrain(lowerer, src, type.elem, locOf(el));
5172
+ if (drained)
5173
+ src = drained;
5174
+ }
5034
5175
  // A native checked iterable can supply scalar elements even when
5035
5176
  // the checker inferred a typed array from its producer. Drain once
5036
5177
  // and validate the elements before the ordinary spread copy.
@@ -5554,7 +5695,7 @@ export function lowerElementAccess(lowerer, expr) {
5554
5695
  // declared number type.
5555
5696
  if (recv.type.kind === "jsval")
5556
5697
  return islandElementRead(lowerer, expr, recv);
5557
- const index = lowerer.lowerExpr(expr.argumentExpression);
5698
+ const index = lowerOptionalNumber(lowerer, lowerer.lowerExpr(expr.argumentExpression), locOf(expr.argumentExpression), expr.argumentExpression);
5558
5699
  if (isJsSourceFile(expr.getSourceFile()) && recv.type.kind === "bytes") {
5559
5700
  return {
5560
5701
  kind: "dynKeyGet",
@@ -5811,36 +5952,12 @@ export function lowerElementAccess(lowerer, expr) {
5811
5952
  }
5812
5953
  }
5813
5954
  if (receiverIr?.kind === "string") {
5814
- // `s[i]` with a number index reads a UTF-16 code unit — charAt's
5815
- // exact job (the UTF-16-exact runtime). Without
5816
- // noUncheckedIndexedAccess the checker types the read `string`,
5817
- // and charAt's "" is the only string-typed answer for an
5818
- // out-of-range or fractional index where JS reads `undefined` —
5819
- // SEMANTICS.md documents the divergence; in-range integer reads
5820
- // (the loop pattern) are JS-exact. Optional results instead retain
5821
- // undefined for missing string properties.
5955
+ // An indexed string property is absent for non-integer and missing
5956
+ // indexes. charAt has different coercion and out-of-range semantics.
5822
5957
  const recv = lowerer.lowerExpr(expr.expression);
5823
- const index = lowerer.lowerExpr(expr.argumentExpression);
5824
- const resultType = lowerer.mapTypeOf(lowerer.typeOf(expr));
5958
+ const index = lowerOptionalNumber(lowerer, lowerer.lowerExpr(expr.argumentExpression), locOf(expr.argumentExpression), expr.argumentExpression);
5825
5959
  if (index.type.kind === "f64" && recv.type.kind === "string") {
5826
- if (resultType?.kind === "string") {
5827
- return {
5828
- kind: "strIntrinsic",
5829
- method: "charAt",
5830
- receiver: recv,
5831
- args: [index],
5832
- type: STRING,
5833
- loc: locOf(expr),
5834
- };
5835
- }
5836
- if (resultType?.kind === "union") {
5837
- const arms = lowerer.unions.get(resultType.unionId)?.arms;
5838
- if (arms?.length === 2 &&
5839
- lowerer.armTag(resultType.unionId, STRING) >= 0 &&
5840
- lowerer.armTag(resultType.unionId, UNDEFINED_T) >= 0) {
5841
- return lowerOptionalStringIndex(lowerer, recv, index, resultType, locOf(expr));
5842
- }
5843
- }
5960
+ return lowerOptionalStringIndex(lowerer, recv, index, lowerer.withUndefinedArm(STRING), locOf(expr));
5844
5961
  }
5845
5962
  lowerer.unsupported("SC1090", expr, "string indexing with this index/result shape (expected a number index and a string or string | undefined result)");
5846
5963
  }
@@ -5962,10 +6079,13 @@ export function lowerElementAccess(lowerer, expr) {
5962
6079
  // change the storage representation or the low-level getter itself.
5963
6080
  if (arr.type.kind === "array") {
5964
6081
  // A non-null assertion is the explicit proven-present form. Preserve
5965
- // the dense getter's established bounds trap here; turning `xs[i]!`
5966
- // into an optional union would change library ABI checks and the
5967
- // existing catchable RangeError contract for an out-of-bounds assert.
5968
- const provenPresent = ts.isNonNullExpression(expr.parent) && expr.parent.expression === expr;
6082
+ // the dense getter's established bounds trap where the asserted value
6083
+ // must be the element type (library ABI checks and the catchable
6084
+ // RangeError contract for an out-of-bounds assert). Where undefined is
6085
+ // representable, the assertion keeps JavaScript's unchecked read.
6086
+ const provenPresent = ts.isNonNullExpression(expr.parent) &&
6087
+ expr.parent.expression === expr &&
6088
+ !assertedElementKeepsUndefined(lowerer, expr.parent);
5969
6089
  if (provenPresent) {
5970
6090
  return lowerer.maybeNarrow({ kind: "arrayGet", arr, index, type: elemT, loc: locOf(expr) }, expr);
5971
6091
  }
@@ -5979,7 +6099,7 @@ export function lowerElementAccess(lowerer, expr) {
5979
6099
  arr.kind === "arrIntrinsic" &&
5980
6100
  arr.method === "slice" &&
5981
6101
  npmStaticPackageOfPath(expr.getSourceFile().fileName) !== null) {
5982
- const safe = lowerNpmStaticSafeIndexRead(lowerer, arr, index, locOf(expr));
6102
+ const safe = lowerSafeIndexRead(lowerer, arr, index, locOf(expr));
5983
6103
  if (safe)
5984
6104
  return safe;
5985
6105
  }
@@ -6225,6 +6345,10 @@ export function lowerAbsenceProbe(lowerer, node) {
6225
6345
  expr = expr.expression;
6226
6346
  }
6227
6347
  if (ts.isPropertyAccessExpression(expr)) {
6348
+ // Namespace members are bindings, not fields of a runtime namespace
6349
+ // object. Their ordinary read already preserves optional storage.
6350
+ if (!expr.questionDotToken && nsMemberIdentOf(lowerer, expr))
6351
+ return null;
6228
6352
  const target = lowerer.fieldTarget(expr);
6229
6353
  if (target?.container === "class" &&
6230
6354
  target.fieldType.kind === "union" &&
@@ -7187,6 +7311,19 @@ export function ensureString(lowerer, e, node) {
7187
7311
  return ensureString(lowerer, { kind: "call", callee: helper, args: [e], type: narrowed, loc: e.loc }, node);
7188
7312
  }
7189
7313
  }
7314
+ if (narrowed?.kind === "union" &&
7315
+ !typeEquals(narrowed, e.type) &&
7316
+ lowerer.unions
7317
+ .get(narrowed.unionId)
7318
+ ?.arms.every((arm) => isUnitType(arm) ||
7319
+ arm.kind === "string" ||
7320
+ arm.kind === "f64" ||
7321
+ arm.kind === "bool" ||
7322
+ arm.kind === "bigint")) {
7323
+ const helper = lowerer.narrowedRetagHelper(node, e.type.unionId, narrowed.unionId, e.loc);
7324
+ if (helper)
7325
+ return ensureString(lowerer, { kind: "call", callee: helper, args: [e], type: narrowed, loc: e.loc }, node);
7326
+ }
7190
7327
  lowerer.unsupported("SC1090", node, `string conversions of unions with object arms (${NARROW_FIRST})`);
7191
7328
  }
7192
7329
  if (e.type.kind === "symbol") {
@@ -7360,20 +7497,16 @@ export function lowerAsExpression(lowerer, expr) {
7360
7497
  };
7361
7498
  }
7362
7499
  }
7363
- // Narrowed reads (`err instanceof Error` proven) still pass below;
7364
- // other targets keep the narrowness fence with the checked-cast fix.
7365
- // In a JS FILE the AsExpression is tsgo's spelling of a JSDoc cast
7366
- // (`/** @type {T} */ (e)` — JS has no `as`); 5.9.3 parsed that as a
7367
- // plain parenthesized read, which lowered caught→dyn and met the
7368
- // target through the ordinary checked-cast coercion — so the dyn
7369
- // bridge stays open here exactly for that shape.
7500
+ // Structural assertions use the ordinary checked dynamic bridge. It
7501
+ // retains primitive values and native class identity before validating
7502
+ // the requested shape; an assertion does not bypass runtime checks.
7370
7503
  const narrowed = lowerer.mapTypeOf(lowerer.typeOf(expr.expression));
7371
7504
  const bridged = narrowed &&
7372
7505
  (narrowed.kind === "f64" ||
7373
7506
  narrowed.kind === "bool" ||
7374
7507
  narrowed.kind === "string" ||
7375
7508
  narrowed.kind === "object" ||
7376
- (narrowed.kind === "dyn" && isJsSourceFile(expr.getSourceFile())));
7509
+ narrowed.kind === "dyn");
7377
7510
  if (!bridged)
7378
7511
  lowerer.unsupported("SC1063", expr);
7379
7512
  }
@@ -7625,11 +7758,11 @@ export function lowerIncDec(lowerer, expr, prefix) {
7625
7758
  }
7626
7759
  fenceNodeModuleMutation(lowerer, access, "assignment");
7627
7760
  if (ts.isPropertyAccessExpression(access)) {
7628
- const target = staticFieldWriteTarget(lowerer, access);
7761
+ const target = staticFieldWriteTarget(lowerer, access) ??
7762
+ expandoWritableTarget(lowerer, access) ??
7763
+ nsWritableTarget(lowerer, access);
7629
7764
  if (target) {
7630
- if (target.type.kind !== "f64")
7631
- lowerer.unsupported("SC1043", expr);
7632
- return { kind: "incDec", op, prefix, localId: target.id, type: F64, loc };
7765
+ return lowerIncDecTarget(lowerer, expr, target, prefix);
7633
7766
  }
7634
7767
  }
7635
7768
  const stmts = [];
@@ -7741,10 +7874,18 @@ export function lowerIncDec(lowerer, expr, prefix) {
7741
7874
  if (!target) {
7742
7875
  lowerer.rejectUnresolved(expr.operand, `increment/decrement of '${expr.operand.text}' (not a writable local or module global)`);
7743
7876
  }
7877
+ return lowerIncDecTarget(lowerer, expr, target, prefix);
7878
+ }
7879
+ /** Numeric updates read the represented slot once and write the computed
7880
+ * value back in that same representation. In particular, an unchecked
7881
+ * indexed initializer can leave undefined in an otherwise numeric binding. */
7882
+ export function lowerIncDecTarget(lowerer, expr, target, prefix) {
7883
+ const loc = locOf(expr);
7884
+ const op = expr.operator === ts.SyntaxKind.PlusPlusToken ? "+" : "-";
7744
7885
  if (target.type.kind === "dyn") {
7745
7886
  const old = lowerer.declareHiddenLocal("%numericOld", DYN);
7746
7887
  const next = lowerer.declareHiddenLocal("%numericNext", DYN);
7747
- const read = lowerer.lowerExpr(expr.operand);
7888
+ const read = varRef(target.id, target.type, loc);
7748
7889
  return {
7749
7890
  kind: "seqExpr",
7750
7891
  stmts: [
@@ -7776,6 +7917,42 @@ export function lowerIncDec(lowerer, expr, prefix) {
7776
7917
  loc,
7777
7918
  };
7778
7919
  }
7920
+ if (target.type.kind === "union") {
7921
+ const read = lowerOptionalNumber(lowerer, varRef(target.id, target.type, loc), loc, expr.operand);
7922
+ if (read.type.kind === "f64") {
7923
+ const old = lowerer.declareHiddenLocal("%numericOld", F64);
7924
+ const next = lowerer.declareHiddenLocal("%numericNext", F64);
7925
+ const result = varRef(prefix ? next.id : old.id, F64, loc);
7926
+ return {
7927
+ kind: "seqExpr",
7928
+ stmts: [
7929
+ { kind: "varDecl", localId: old.id, init: read, loc },
7930
+ {
7931
+ kind: "varDecl",
7932
+ localId: next.id,
7933
+ init: {
7934
+ kind: "bin",
7935
+ op,
7936
+ left: varRef(old.id, F64, loc),
7937
+ right: numLit(1, loc),
7938
+ type: F64,
7939
+ loc,
7940
+ },
7941
+ loc,
7942
+ },
7943
+ {
7944
+ kind: "assign",
7945
+ localId: target.id,
7946
+ value: lowerer.coerceInto(expr.operand, varRef(next.id, F64, loc), target.type),
7947
+ loc,
7948
+ },
7949
+ ],
7950
+ result,
7951
+ type: F64,
7952
+ loc,
7953
+ };
7954
+ }
7955
+ }
7779
7956
  if (target.type.kind !== "f64")
7780
7957
  lowerer.unsupported("SC1043", expr);
7781
7958
  return { kind: "incDec", op, prefix, localId: target.id, type: F64, loc };
@@ -8136,6 +8313,9 @@ export function lowerBinary(lowerer, expr) {
8136
8313
  const recv = tryLowerExpression(lowerer, expr.left.expression);
8137
8314
  if (recv && recv.type.kind === "dyn")
8138
8315
  return lowerDynMemberAssignment(lowerer, expr, recv);
8316
+ const unionWrite = lowerUnionFieldWrite(lowerer, expr.left, expr.right);
8317
+ if (unionWrite)
8318
+ return unionWrite;
8139
8319
  const field = lowerer.fieldTarget(expr.left);
8140
8320
  if (field) {
8141
8321
  const recvTmp = lowerer.declareHiddenLocal("%setReceiver", field.obj.type);
@@ -8721,7 +8901,7 @@ export function lowerBinary(lowerer, expr) {
8721
8901
  const optionalStringPlus = lowerOptionalStringPlus();
8722
8902
  if (optionalStringPlus)
8723
8903
  return optionalStringPlus;
8724
- if (isJsSourceFile(expr.getSourceFile())) {
8904
+ {
8725
8905
  const primitive = (type) => type.kind === "f64" ||
8726
8906
  type.kind === "string" ||
8727
8907
  type.kind === "bool" ||
@@ -8827,6 +9007,13 @@ export function lowerBinary(lowerer, expr) {
8827
9007
  if (unitTest)
8828
9008
  return unitTest;
8829
9009
  if (left.type.kind === "union" || right.type.kind === "union") {
9010
+ const compared = lowerUnionEquality(lowerer, left, right, negated, false, loc);
9011
+ if (compared)
9012
+ return compared;
9013
+ const aliasRefusal = (type) => {
9014
+ if (tagEqualityMayMissAlias(lowerer, type))
9015
+ lowerer.unsupported("SC1090", expr, `comparisons of related class values beside structural union members (${NARROW_FIRST})`);
9016
+ };
8830
9017
  // JS strict equality of the ARM values, per union tag (a
8831
9018
  // per-union helper): equal tags compare payloads (f64 ==, string
8832
9019
  // bytes, bool ==, ref-arm POINTER identity), different tags are
@@ -8862,6 +9049,7 @@ export function lowerBinary(lowerer, expr) {
8862
9049
  };
8863
9050
  }
8864
9051
  if ((sameUnion || !bothUnion) && lowerer.eqComparableUnion(ut.unionId)) {
9052
+ aliasRefusal(ut);
8865
9053
  return {
8866
9054
  kind: "unionEq",
8867
9055
  unionId: ut.unionId,
@@ -8892,6 +9080,7 @@ export function lowerBinary(lowerer, expr) {
8892
9080
  kind: "union",
8893
9081
  unionId: lowerer.unions.intern(arms),
8894
9082
  };
9083
+ aliasRefusal(common);
8895
9084
  return {
8896
9085
  kind: "unionEq",
8897
9086
  unionId: common.unionId,
@@ -10037,17 +10226,30 @@ export function caughtRead(lowerer, node, local, loc) {
10037
10226
  }
10038
10227
  if (narrowed?.kind === "object") {
10039
10228
  const info = lowerer.classes.get(narrowed.className);
10040
- if (info && lowerer.inHierarchy(info)) {
10041
- return { kind: "caughtNarrow", value: ref, type: narrowed, loc };
10229
+ if (info) {
10230
+ const value = { kind: "caughtNarrow", value: ref, type: narrowed, loc };
10231
+ if (lowerer.inHierarchy(info))
10232
+ return value;
10233
+ return {
10234
+ kind: "ternary",
10235
+ cond: {
10236
+ kind: "caughtTest",
10237
+ value: ref,
10238
+ test: "instanceof",
10239
+ className: info.def.name,
10240
+ type: BOOL,
10241
+ loc,
10242
+ },
10243
+ then: value,
10244
+ else_: lowerer.coerceInto(node, { kind: "caughtToDyn", value: ref, type: DYN, loc }, narrowed),
10245
+ type: narrowed,
10246
+ loc,
10247
+ };
10042
10248
  }
10043
10249
  }
10044
- // An UN-narrowed use — the occurrence still types `unknown` — converts
10045
- // to a dyn value (`options.onError?.(error)` — the caught snapshot
10046
- // flowing into an unknown slot): the typed→unknown deep-copy stance
10047
- // extended to exception payloads. Error payloads keep their
10048
- // observability (instanceof Error / .message / String() — the checked-dynamic tree's
10049
- // error encoding); other object payloads are type-erased at runtime and
10050
- // convert to the "[object Object]" approximation — SEMANTICS.md 67.
10250
+ // Unnarrowed reads cross into unknown. The caught-value dispatch pass
10251
+ // retains known native class payloads through live identity capsules;
10252
+ // other payload kinds use the runtime's ordinary conversion.
10051
10253
  if (narrowed?.kind === "dyn") {
10052
10254
  return { kind: "caughtToDyn", value: ref, type: DYN, loc };
10053
10255
  }
@@ -10113,6 +10315,38 @@ export function lowerInstanceOf(lowerer, expr, loc) {
10113
10315
  (lowerer.isStdlibGlobal(expr.right, "Set") || lowerer.isStdlibGlobal(expr.right, "Map"))) {
10114
10316
  const collection = lowerer.isStdlibGlobal(expr.right, "Map") ? "map" : "set";
10115
10317
  const value = lowerer.lowerExpr(expr.left);
10318
+ if (value.type.kind === "union") {
10319
+ const union = lowerer.unions.get(value.type.unionId);
10320
+ if (union) {
10321
+ const local = lowerer.declareHiddenLocal("%collectionTest", value.type);
10322
+ const reference = varRef(local.id, value.type, loc);
10323
+ let result = { kind: "boolLit", value: false, type: BOOL, loc };
10324
+ union.arms.forEach((arm, tag) => {
10325
+ if (arm.kind !== collection)
10326
+ return;
10327
+ const test = {
10328
+ kind: "unionIsTag",
10329
+ unionId: union.id,
10330
+ value: reference,
10331
+ tag,
10332
+ negated: false,
10333
+ type: BOOL,
10334
+ loc,
10335
+ };
10336
+ result =
10337
+ result.kind === "boolLit"
10338
+ ? test
10339
+ : { kind: "logical", op: "||", left: result, right: test, type: BOOL, loc };
10340
+ });
10341
+ return {
10342
+ kind: "seqExpr",
10343
+ stmts: [{ kind: "varDecl", localId: local.id, init: value, loc }],
10344
+ result,
10345
+ type: BOOL,
10346
+ loc,
10347
+ };
10348
+ }
10349
+ }
10116
10350
  if (value.type.kind === "dyn")
10117
10351
  return {
10118
10352
  kind: "libCall",
@@ -10390,8 +10624,22 @@ export function lowerInstanceOf(lowerer, expr, loc) {
10390
10624
  const caughtLocal = lowerer.caughtLocalOf(expr.left);
10391
10625
  if (caughtLocal) {
10392
10626
  if (!lowerer.inHierarchy(target)) {
10393
- lowerer.unsupported("SC1090", expr, `'instanceof' on a catch binding against the standalone class '${target.def.name}' ` +
10394
- `(only classes in extends hierarchies carry the vtable the payload test needs)`);
10627
+ const value = varRef(caughtLocal.id, CAUGHT, loc);
10628
+ return {
10629
+ kind: "ternary",
10630
+ cond: {
10631
+ kind: "caughtTest",
10632
+ value,
10633
+ test: "instanceof",
10634
+ className: target.def.name,
10635
+ type: BOOL,
10636
+ loc,
10637
+ },
10638
+ then: { kind: "boolLit", value: true, type: BOOL, loc },
10639
+ else_: classInstanceOf(lowerer, { kind: "caughtToDyn", value, type: DYN, loc }, target, loc),
10640
+ type: BOOL,
10641
+ loc,
10642
+ };
10395
10643
  }
10396
10644
  return {
10397
10645
  kind: "caughtTest",
@@ -10689,11 +10937,10 @@ function lowerPrivateIn(lowerer, expr, priv, loc) {
10689
10937
  * type-directed: a declared non-optional field is a compile-time `true`,
10690
10938
  * a missing field (no index signature) a compile-time `false` — both
10691
10939
  * folds limited to side-effect-free receivers, the lowerInstanceOf rule —
10692
- * and an OPTIONAL field (undefined-armed union) is a runtime tag test on
10693
- * the slot: present iff the arm is not undefined. That last case is the
10694
- * representation's honest answer — a field explicitly assigned
10695
- * `undefined` reads as absent (`"a" in {a: undefined}` is true in JS,
10696
- * false here; SEMANTICS.md 55). Union receivers (the `in`-narrowing
10940
+ * and an OPTIONAL field (undefined-armed union) is a runtime presence
10941
+ * test on the slot: an omitted or deleted property is absent, while a
10942
+ * property explicitly holding `undefined` is present, as in JS
10943
+ * (`"a" in {a: undefined}` is true). Union receivers (the `in`-narrowing
10697
10944
  * idiom over multiple shapes), index-signature keys, class instances,
10698
10945
  * and dyn/unknown stay fenced. Keys are literal strings — a computed key
10699
10946
  * over a shape would need the runtime key table. */
@@ -10737,13 +10984,42 @@ function lowerInExpression(lowerer, expr, loc) {
10737
10984
  }
10738
10985
  }
10739
10986
  }
10987
+ // A RUNTIME numeric key over an ARRAY receiver (`if (i in arr)` in a
10988
+ // loop) asks the same slot/property presence query as the literal fold
10989
+ // above and `Object.hasOwn`. The checked-dynamic fallback below would
10990
+ // box the receiver and materialize every element on each evaluation,
10991
+ // which makes such loops quadratic. A Number key never names an
10992
+ // inherited property: neither Array.prototype nor Object.prototype has
10993
+ // index-like or numeric-string keys. JS evaluates the key before the
10994
+ // receiver, so the key is stabilized in a hidden local first.
10995
+ if (lowerer.mapTypeOf(lowerer.typeOf(expr.left))?.kind === "f64" &&
10996
+ lowerer.mapTypeOf(lowerer.typeOf(expr.right))?.kind === "array") {
10997
+ const k = lowerer.lowerExpr(expr.left);
10998
+ const recvArr = lowerer.lowerExpr(expr.right);
10999
+ if (k.type.kind === "f64" && recvArr.type.kind === "array") {
11000
+ const keyLocal = lowerer.declareHiddenLocal("%inIndex", F64);
11001
+ return {
11002
+ kind: "seqExpr",
11003
+ stmts: [{ kind: "varDecl", localId: keyLocal.id, init: k, loc }],
11004
+ result: {
11005
+ kind: "arrayHas",
11006
+ arr: recvArr,
11007
+ index: varRef(keyLocal.id, F64, loc),
11008
+ type: BOOL,
11009
+ loc,
11010
+ },
11011
+ type: BOOL,
11012
+ loc,
11013
+ };
11014
+ }
11015
+ }
10740
11016
  const key = foldedStringKeyOf(lowerer, expr.left);
10741
11017
  if (key === null) {
10742
11018
  // A RUNTIME string key over an INDEX-SIGNATURE record receiver (the
10743
11019
  // `names.filter((k) => k in config)` idiom): the interned key-
10744
11020
  // presence helper — declared fields answer statically per name
10745
- // (optional slots per value: the undefined arm reads absent, stance
10746
- // 55), then the overflow map's live keys. Other receivers keep the
11021
+ // (optional slots by their runtime presence), then the overflow
11022
+ // map's live keys. Other receivers keep the
10747
11023
  // fence: fixed shapes want the literal folds above, and there is no
10748
11024
  // runtime key table to ask.
10749
11025
  const rIn = lowerRuntimeKeyIn(lowerer, expr, loc);
@@ -10986,24 +11262,9 @@ function lowerInExpression(lowerer, expr, loc) {
10986
11262
  const field = shape.fields.find((f) => f.name === key);
10987
11263
  if (field) {
10988
11264
  if (field.type.kind === "union" && lowerer.armTag(field.type.unionId, UNDEFINED_T) >= 0) {
10989
- // Optional slot: the key is present iff the arm is not undefined.
10990
- const read = {
10991
- kind: "recordGet",
10992
- obj: recv,
10993
- shapeId: recv.type.shapeId,
10994
- field: key,
10995
- type: field.type,
10996
- loc,
10997
- };
10998
- return {
10999
- kind: "unionIsTag",
11000
- unionId: field.type.unionId,
11001
- tag: lowerer.armTag(field.type.unionId, UNDEFINED_T),
11002
- negated: true,
11003
- value: read,
11004
- type: BOOL,
11005
- loc,
11006
- };
11265
+ // Optional slot: the key is present unless the field is absent
11266
+ // (omitted or deleted); an explicit undefined is present.
11267
+ return lowerer.recordFieldPresent(recv, recv.type.shapeId, key, loc);
11007
11268
  }
11008
11269
  // A declared non-optional field always exists on every value of the
11009
11270
  // shape — statically true, but folding may only drop a
@@ -11043,9 +11304,9 @@ function lowerInExpression(lowerer, expr, loc) {
11043
11304
  * runtime string and r an index-signature record — an interned
11044
11305
  * `%rec.haskey.<n>(k, r)` walks the declared names (a string-equality
11045
11306
  * chain: non-optional fields and accessor slots answer true, optional
11046
- * slots answer their per-value tag test) and then the overflow map's
11047
- * live keys. Null when the pair is outside that shape (the caller keeps
11048
- * its fence). */
11307
+ * slots answer their per-value tag test) and then probes the overflow
11308
+ * map's hashed key set. Null when the pair is outside that shape (the
11309
+ * caller keeps its fence). */
11049
11310
  function lowerRuntimeKeyIn(lowerer, expr, loc) {
11050
11311
  if (lowerer.mapTypeOf(lowerer.typeOf(expr.left))?.kind !== "string")
11051
11312
  return null;
@@ -11080,62 +11341,15 @@ function lowerRuntimeKeyIn(lowerer, expr, loc) {
11080
11341
  type: BOOL,
11081
11342
  loc,
11082
11343
  };
11083
- const utag = !accessor && f.type.kind === "union" ? lowerer.armTag(f.type.unionId, UNDEFINED_T) : -1;
11084
- const answer = utag >= 0 && f.type.kind === "union"
11085
- ? {
11086
- kind: "unionIsTag",
11087
- unionId: f.type.unionId,
11088
- tag: utag,
11089
- negated: true,
11090
- value: {
11091
- kind: "recordGet",
11092
- obj: r,
11093
- shapeId: recvT.shapeId,
11094
- field: f.name,
11095
- type: f.type,
11096
- loc,
11097
- },
11098
- type: BOOL,
11099
- loc,
11100
- }
11101
- : { kind: "boolLit", value: true, type: BOOL, loc };
11344
+ const answer = accessor
11345
+ ? { kind: "boolLit", value: true, type: BOOL, loc }
11346
+ : lowerer.recordFieldPresent(r, recvT.shapeId, f.name, loc);
11102
11347
  body.push({ kind: "if", cond: eq, then: [ret(answer)], else_: null, loc });
11103
11348
  }
11104
- const ksT = arrayOf(STRING);
11105
- body.push({
11106
- kind: "varDecl",
11107
- localId: "ks.0",
11108
- init: { kind: "recordOvfKeys", obj: r, shapeId: recvT.shapeId, type: ksT, loc },
11109
- loc,
11110
- }, countedFor(loc, {
11111
- kind: "arrIntrinsic",
11112
- method: "length",
11113
- receiver: varRef("ks.0", ksT, loc),
11114
- args: [],
11115
- type: F64,
11116
- loc,
11117
- }, () => [
11118
- {
11119
- kind: "if",
11120
- cond: {
11121
- kind: "strEq",
11122
- negated: false,
11123
- left: k,
11124
- right: {
11125
- kind: "arrayGet",
11126
- arr: varRef("ks.0", ksT, loc),
11127
- index: varRef("i.0", F64, loc),
11128
- type: STRING,
11129
- loc,
11130
- },
11131
- type: BOOL,
11132
- loc,
11133
- },
11134
- then: [ret({ kind: "boolLit", value: true, type: BOOL, loc })],
11135
- else_: null,
11136
- loc,
11137
- },
11138
- ]), ret({ kind: "boolLit", value: false, type: BOOL, loc }));
11349
+ // Overflow keys answer through the map's hashed presence probe (a
11350
+ // stored undefined value is still present), not a scan over a fresh
11351
+ // key snapshot, which made `k in dict` loops quadratic.
11352
+ body.push(ret({ kind: "recordOvfHas", obj: r, shapeId: recvT.shapeId, key: k, type: BOOL, loc }));
11139
11353
  lowerer.liftedFns.push({
11140
11354
  name: helper,
11141
11355
  params: [
@@ -11146,8 +11360,6 @@ function lowerRuntimeKeyIn(lowerer, expr, loc) {
11146
11360
  locals: [
11147
11361
  { id: "k.0", name: "k", type: STRING, mutable: true },
11148
11362
  { id: "r.0", name: "r", type: recT, mutable: true },
11149
- { id: "ks.0", name: "ks", type: ksT, mutable: false },
11150
- { id: "i.0", name: "i", type: F64, mutable: true },
11151
11363
  ],
11152
11364
  body,
11153
11365
  loc,
@@ -11835,7 +12047,7 @@ export function lowerUnionProperty(lowerer, expr) {
11835
12047
  return null;
11836
12048
  }
11837
12049
  if (value.type.kind !== "union") {
11838
- throw new InternalCompilerError("lowerer bug: union-typed receiver lowered to a non-union");
12050
+ lowerer.unsupported("SC1090", expr, "shared property access without a represented union receiver");
11839
12051
  }
11840
12052
  const def = lowerer.unions.get(value.type.unionId);
11841
12053
  if (!def)
@@ -12212,11 +12424,32 @@ export function fieldTarget(lowerer, access) {
12212
12424
  const stored = ts.isIdentifier(access.expression)
12213
12425
  ? (lowerer.peekLocal(access.expression)?.type ?? lowerer.globalOf(access.expression)?.type)
12214
12426
  : undefined;
12215
- const receiverIr = stored?.kind === "record" || stored?.kind === "object"
12427
+ const narrowed = lowerer.mapTypeOf(lowerer.typeOf(access.expression));
12428
+ // Structural record views retain their storage layout, while a nominal
12429
+ // subclass guard proves a more specific layout of the same object.
12430
+ const receiverIr = stored?.kind === "record"
12216
12431
  ? stored
12217
- : lowerer.mapTypeOf(lowerer.typeOf(access.expression));
12432
+ : stored?.kind === "object" &&
12433
+ !(narrowed?.kind === "object" &&
12434
+ lowerer.isSubclassOf(narrowed.className, stored.className))
12435
+ ? stored
12436
+ : narrowed;
12218
12437
  if (receiverIr?.kind === "object") {
12219
- return classFieldTarget(lowerer, access.expression, receiverIr, access.name.text);
12438
+ const target = classFieldTarget(lowerer, access.expression, receiverIr, access.name.text);
12439
+ if (target)
12440
+ return target;
12441
+ // Abstract properties declare no base storage. Resolve the concrete
12442
+ // instance's live field or accessor through the existing class bridge;
12443
+ // inventing a shared field offset would misread subclass layouts.
12444
+ if (abstractPropertyDeclOf(lowerer, access)) {
12445
+ return {
12446
+ container: "dynamic",
12447
+ obj: lowerer.coerceInto(access.expression, lowerer.lowerExpr(access.expression), DYN),
12448
+ field: access.name.text,
12449
+ fieldType: lowerer.irTypeOf(access),
12450
+ };
12451
+ }
12452
+ return null;
12220
12453
  }
12221
12454
  if (receiverIr?.kind === "union" && hasClassPayload(lowerer, receiverIr)) {
12222
12455
  return representedClassFieldTarget(lowerer, access.expression, access.name.text, lowerer.lowerExpr(access.expression));
@@ -12457,13 +12690,13 @@ function symbolFieldTarget(lowerer, expr) {
12457
12690
  * undefined, which these property types cannot represent. */
12458
12691
  export function fieldGetExpr(lowerer, target, loc, blame) {
12459
12692
  if (target.container === "dynamic")
12460
- return {
12693
+ return lowerer.coerceInto(blame, {
12461
12694
  kind: "dynKeyGet",
12462
12695
  value: target.obj,
12463
12696
  key: { kind: "strLit", value: target.field, type: STRING, loc },
12464
12697
  type: DYN,
12465
12698
  loc,
12466
- };
12699
+ }, target.fieldType);
12467
12700
  if (target.container === "class" &&
12468
12701
  (target.field === "message" || target.field === "name") &&
12469
12702
  (target.className === "%Error" || lowerer.isSubclassOf(target.className, "%Error")))