@scriptc/compiler 0.2.1 → 0.2.3

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 (315) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +158 -31
  2. package/dist/backend/cycle-analysis.js +63 -50
  3. package/dist/backend/cycle-analysis.js.map +1 -1
  4. package/dist/backend/cycle-analysis.test.js +51 -0
  5. package/dist/backend/cycle-analysis.test.js.map +1 -1
  6. package/dist/backend/llvm/borrowed-receivers.d.ts +9 -0
  7. package/dist/backend/llvm/borrowed-receivers.js +58 -0
  8. package/dist/backend/llvm/borrowed-receivers.js.map +1 -0
  9. package/dist/backend/llvm/call-lifetimes.d.ts +20 -0
  10. package/dist/backend/llvm/call-lifetimes.js +179 -0
  11. package/dist/backend/llvm/call-lifetimes.js.map +1 -0
  12. package/dist/backend/llvm/call-lifetimes.test.d.ts +1 -0
  13. package/dist/backend/llvm/call-lifetimes.test.js +205 -0
  14. package/dist/backend/llvm/call-lifetimes.test.js.map +1 -0
  15. package/dist/backend/llvm/dyn.d.ts +5 -2
  16. package/dist/backend/llvm/dyn.js +163 -47
  17. package/dist/backend/llvm/dyn.js.map +1 -1
  18. package/dist/backend/llvm/emitter.d.ts +37 -1
  19. package/dist/backend/llvm/emitter.js +209 -21
  20. package/dist/backend/llvm/emitter.js.map +1 -1
  21. package/dist/backend/llvm/emitter.test.js +29 -2
  22. package/dist/backend/llvm/emitter.test.js.map +1 -1
  23. package/dist/backend/llvm/expr-async.js +1 -1
  24. package/dist/backend/llvm/expr-async.js.map +1 -1
  25. package/dist/backend/llvm/expr-calls.js +42 -5
  26. package/dist/backend/llvm/expr-calls.js.map +1 -1
  27. package/dist/backend/llvm/expr-containers.js +75 -13
  28. package/dist/backend/llvm/expr-containers.js.map +1 -1
  29. package/dist/backend/llvm/expr-dynamic.js +31 -6
  30. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  31. package/dist/backend/llvm/expr-primitives.js +6 -5
  32. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  33. package/dist/backend/llvm/expr-records.js +1 -1
  34. package/dist/backend/llvm/expr-records.js.map +1 -1
  35. package/dist/backend/llvm/expr-stream-bridges.js +75 -19
  36. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  37. package/dist/backend/llvm/expr-stream-callbacks.d.ts +2 -2
  38. package/dist/backend/llvm/expr-stream-callbacks.js +7 -57
  39. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
  40. package/dist/backend/llvm/lib-dispatch.js +41 -3
  41. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  42. package/dist/backend/llvm/lib-filesystem.js +12 -9
  43. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  44. package/dist/backend/llvm/lib-shared.js +70 -2
  45. package/dist/backend/llvm/lib-shared.js.map +1 -1
  46. package/dist/backend/llvm/local-array-reads.d.ts +44 -0
  47. package/dist/backend/llvm/local-array-reads.js +313 -0
  48. package/dist/backend/llvm/local-array-reads.js.map +1 -0
  49. package/dist/backend/llvm/local-array-reads.test.d.ts +1 -0
  50. package/dist/backend/llvm/local-array-reads.test.js +446 -0
  51. package/dist/backend/llvm/local-array-reads.test.js.map +1 -0
  52. package/dist/backend/llvm/map-read-lifetimes.d.ts +36 -0
  53. package/dist/backend/llvm/map-read-lifetimes.js +128 -0
  54. package/dist/backend/llvm/map-read-lifetimes.js.map +1 -0
  55. package/dist/backend/llvm/map-read-lifetimes.test.d.ts +1 -0
  56. package/dist/backend/llvm/map-read-lifetimes.test.js +123 -0
  57. package/dist/backend/llvm/map-read-lifetimes.test.js.map +1 -0
  58. package/dist/backend/llvm/shapes.js +1 -0
  59. package/dist/backend/llvm/shapes.js.map +1 -1
  60. package/dist/backend/llvm/split.js +15 -5
  61. package/dist/backend/llvm/split.js.map +1 -1
  62. package/dist/backend/llvm/split.test.js +17 -0
  63. package/dist/backend/llvm/split.test.js.map +1 -1
  64. package/dist/backend/llvm/stack-unions.d.ts +20 -0
  65. package/dist/backend/llvm/stack-unions.js +61 -0
  66. package/dist/backend/llvm/stack-unions.js.map +1 -0
  67. package/dist/backend/llvm/stack-unions.test.d.ts +1 -0
  68. package/dist/backend/llvm/stack-unions.test.js +241 -0
  69. package/dist/backend/llvm/stack-unions.test.js.map +1 -0
  70. package/dist/backend/llvm/string-lifetimes.d.ts +12 -0
  71. package/dist/backend/llvm/string-lifetimes.js +70 -0
  72. package/dist/backend/llvm/string-lifetimes.js.map +1 -0
  73. package/dist/backend/llvm/string-lifetimes.test.d.ts +1 -0
  74. package/dist/backend/llvm/string-lifetimes.test.js +230 -0
  75. package/dist/backend/llvm/string-lifetimes.test.js.map +1 -0
  76. package/dist/backend/mangle.d.ts +2 -0
  77. package/dist/backend/mangle.js +4 -0
  78. package/dist/backend/mangle.js.map +1 -1
  79. package/dist/backend/may-throw.js +71 -29
  80. package/dist/backend/may-throw.js.map +1 -1
  81. package/dist/backend/may-throw.test.js +104 -1
  82. package/dist/backend/may-throw.test.js.map +1 -1
  83. package/dist/backend/native-codegen.d.ts +1 -1
  84. package/dist/backend/native-codegen.js +4 -3
  85. package/dist/backend/native-codegen.js.map +1 -1
  86. package/dist/backend/native-codegen.test.js +11 -0
  87. package/dist/backend/native-codegen.test.js.map +1 -1
  88. package/dist/backend/native-toolchain.d.ts +2 -2
  89. package/dist/backend/native-toolchain.js +2 -0
  90. package/dist/backend/native-toolchain.js.map +1 -1
  91. package/dist/backend/target-diagnostics.d.ts +5 -0
  92. package/dist/backend/target-diagnostics.js +72 -1
  93. package/dist/backend/target-diagnostics.js.map +1 -1
  94. package/dist/backend/target-diagnostics.test.d.ts +1 -0
  95. package/dist/backend/target-diagnostics.test.js +68 -0
  96. package/dist/backend/target-diagnostics.test.js.map +1 -0
  97. package/dist/coverage/surface-manifest.js +5 -3
  98. package/dist/coverage/surface-manifest.js.map +1 -1
  99. package/dist/executable/executable-cache.d.ts +7 -3
  100. package/dist/executable/executable-cache.js +47 -11
  101. package/dist/executable/executable-cache.js.map +1 -1
  102. package/dist/executable/executable-cache.test.js +109 -2
  103. package/dist/executable/executable-cache.test.js.map +1 -1
  104. package/dist/executable/prepare.js +2 -1
  105. package/dist/executable/prepare.js.map +1 -1
  106. package/dist/frontend/builtin-modules.d.ts +1 -1
  107. package/dist/frontend/builtin-modules.js +1 -1
  108. package/dist/frontend/builtin-modules.js.map +1 -1
  109. package/dist/frontend/function-completion.d.ts +6 -0
  110. package/dist/frontend/function-completion.js +50 -0
  111. package/dist/frontend/function-completion.js.map +1 -0
  112. package/dist/frontend/input-tracker.js +3 -3
  113. package/dist/frontend/input-tracker.js.map +1 -1
  114. package/dist/frontend/input-tracker.test.js +38 -2
  115. package/dist/frontend/input-tracker.test.js.map +1 -1
  116. package/dist/frontend/lowering/abstract-equality.js +5 -1
  117. package/dist/frontend/lowering/abstract-equality.js.map +1 -1
  118. package/dist/frontend/lowering/checked-iterable-spread.d.ts +4 -0
  119. package/dist/frontend/lowering/checked-iterable-spread.js +30 -0
  120. package/dist/frontend/lowering/checked-iterable-spread.js.map +1 -0
  121. package/dist/frontend/lowering/checked-promise-all.d.ts +5 -0
  122. package/dist/frontend/lowering/checked-promise-all.js +31 -0
  123. package/dist/frontend/lowering/checked-promise-all.js.map +1 -0
  124. package/dist/frontend/lowering/class-callbacks.d.ts +1 -1
  125. package/dist/frontend/lowering/class-callbacks.js +7 -6
  126. package/dist/frontend/lowering/class-callbacks.js.map +1 -1
  127. package/dist/frontend/lowering/class-construction.d.ts +2 -0
  128. package/dist/frontend/lowering/class-construction.js +34 -5
  129. package/dist/frontend/lowering/class-construction.js.map +1 -1
  130. package/dist/frontend/lowering/class-descriptors.d.ts +1 -1
  131. package/dist/frontend/lowering/class-descriptors.js +12 -5
  132. package/dist/frontend/lowering/class-descriptors.js.map +1 -1
  133. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +25 -0
  134. package/dist/frontend/lowering/class-dynamic-dispatch.js +597 -78
  135. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  136. package/dist/frontend/lowering/class-dynamic-dispatch.test.js +64 -2
  137. package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
  138. package/dist/frontend/lowering/class-instance-constructor.d.ts +1 -1
  139. package/dist/frontend/lowering/class-instance-constructor.js +11 -41
  140. package/dist/frontend/lowering/class-instance-constructor.js.map +1 -1
  141. package/dist/frontend/lowering/class-method-values.d.ts +16 -0
  142. package/dist/frontend/lowering/class-method-values.js +60 -29
  143. package/dist/frontend/lowering/class-method-values.js.map +1 -1
  144. package/dist/frontend/lowering/class-prototypes.d.ts +5 -1
  145. package/dist/frontend/lowering/class-prototypes.js +69 -10
  146. package/dist/frontend/lowering/class-prototypes.js.map +1 -1
  147. package/dist/frontend/lowering/class-runtime-statics.d.ts +4 -4
  148. package/dist/frontend/lowering/class-runtime-statics.js +26 -8
  149. package/dist/frontend/lowering/class-runtime-statics.js.map +1 -1
  150. package/dist/frontend/lowering/class-static-data.d.ts +1 -0
  151. package/dist/frontend/lowering/class-static-data.js +4 -2
  152. package/dist/frontend/lowering/class-static-data.js.map +1 -1
  153. package/dist/frontend/lowering/collection-ingestion.d.ts +31 -0
  154. package/dist/frontend/lowering/collection-ingestion.js +215 -0
  155. package/dist/frontend/lowering/collection-ingestion.js.map +1 -0
  156. package/dist/frontend/lowering/containers/bytes.js +19 -4
  157. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  158. package/dist/frontend/lowering/containers/string-and-regexp.js +6 -1
  159. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  160. package/dist/frontend/lowering/deferred-module-initializers.d.ts +13 -0
  161. package/dist/frontend/lowering/deferred-module-initializers.js +410 -0
  162. package/dist/frontend/lowering/deferred-module-initializers.js.map +1 -0
  163. package/dist/frontend/lowering/deferred-module-initializers.test.d.ts +1 -0
  164. package/dist/frontend/lowering/deferred-module-initializers.test.js +92 -0
  165. package/dist/frontend/lowering/deferred-module-initializers.test.js.map +1 -0
  166. package/dist/frontend/lowering/expressions/object-literals.js +31 -1
  167. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  168. package/dist/frontend/lowering/expressions/optional-chains.js +3 -3
  169. package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
  170. package/dist/frontend/lowering/import-meta.d.ts +10 -0
  171. package/dist/frontend/lowering/import-meta.js +52 -0
  172. package/dist/frontend/lowering/import-meta.js.map +1 -0
  173. package/dist/frontend/lowering/lower-assert.js +105 -41
  174. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  175. package/dist/frontend/lowering/lower-builtin-values.d.ts +2 -0
  176. package/dist/frontend/lowering/lower-builtin-values.js +22 -1
  177. package/dist/frontend/lowering/lower-builtin-values.js.map +1 -1
  178. package/dist/frontend/lowering/lower-builtins.d.ts +7 -22
  179. package/dist/frontend/lowering/lower-builtins.js +439 -95
  180. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  181. package/dist/frontend/lowering/lower-calls.js +289 -76
  182. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  183. package/dist/frontend/lowering/lower-classes.d.ts +5 -0
  184. package/dist/frontend/lowering/lower-classes.js +443 -29
  185. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  186. package/dist/frontend/lowering/lower-containers.d.ts +6 -2
  187. package/dist/frontend/lowering/lower-containers.js +79 -20
  188. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  189. package/dist/frontend/lowering/lower-exprs.d.ts +10 -6
  190. package/dist/frontend/lowering/lower-exprs.js +329 -170
  191. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  192. package/dist/frontend/lowering/lower-generators.js +5 -1
  193. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  194. package/dist/frontend/lowering/lower-inspect.js +58 -1
  195. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  196. package/dist/frontend/lowering/lower-island.js +4 -0
  197. package/dist/frontend/lowering/lower-island.js.map +1 -1
  198. package/dist/frontend/lowering/lower-island.test.d.ts +1 -0
  199. package/dist/frontend/lowering/lower-island.test.js +51 -0
  200. package/dist/frontend/lowering/lower-island.test.js.map +1 -0
  201. package/dist/frontend/lowering/lower-modules.d.ts +1 -3
  202. package/dist/frontend/lowering/lower-modules.js +186 -82
  203. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  204. package/dist/frontend/lowering/lower-modules.test.js +69 -1
  205. package/dist/frontend/lowering/lower-modules.test.js.map +1 -1
  206. package/dist/frontend/lowering/lower-stmts.js +172 -103
  207. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  208. package/dist/frontend/lowering/lower-stmts.test.d.ts +1 -0
  209. package/dist/frontend/lowering/lower-stmts.test.js +77 -0
  210. package/dist/frontend/lowering/lower-stmts.test.js.map +1 -0
  211. package/dist/frontend/lowering/lower-stream.js +2 -0
  212. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  213. package/dist/frontend/lowering/lower-system-errors.d.ts +6 -0
  214. package/dist/frontend/lowering/lower-system-errors.js +29 -0
  215. package/dist/frontend/lowering/lower-system-errors.js.map +1 -0
  216. package/dist/frontend/lowering/lower-url.d.ts +2 -1
  217. package/dist/frontend/lowering/lower-url.js +32 -9
  218. package/dist/frontend/lowering/lower-url.js.map +1 -1
  219. package/dist/frontend/lowering/lowerer.d.ts +30 -12
  220. package/dist/frontend/lowering/lowerer.js +268 -49
  221. package/dist/frontend/lowering/lowerer.js.map +1 -1
  222. package/dist/frontend/lowering/lowerer.test.js +38 -0
  223. package/dist/frontend/lowering/lowerer.test.js.map +1 -1
  224. package/dist/frontend/lowering/module-namespace-elements.d.ts +7 -0
  225. package/dist/frontend/lowering/module-namespace-elements.js +54 -0
  226. package/dist/frontend/lowering/module-namespace-elements.js.map +1 -0
  227. package/dist/frontend/lowering/object-factory-new.d.ts +4 -3
  228. package/dist/frontend/lowering/object-factory-new.js +27 -14
  229. package/dist/frontend/lowering/object-factory-new.js.map +1 -1
  230. package/dist/frontend/lowering/surfaces.d.ts +3 -2
  231. package/dist/frontend/lowering/surfaces.js +93 -33
  232. package/dist/frontend/lowering/surfaces.js.map +1 -1
  233. package/dist/frontend/lowering/text-decoder-encoding.js +3 -0
  234. package/dist/frontend/lowering/text-decoder-encoding.js.map +1 -1
  235. package/dist/frontend/lowering/text-decoder-encoding.test.js +2 -1
  236. package/dist/frontend/lowering/text-decoder-encoding.test.js.map +1 -1
  237. package/dist/frontend/module-syntax.d.ts +1 -1
  238. package/dist/frontend/module-syntax.js +8 -1
  239. package/dist/frontend/module-syntax.js.map +1 -1
  240. package/dist/frontend/module-syntax.test.js +10 -0
  241. package/dist/frontend/module-syntax.test.js.map +1 -1
  242. package/dist/frontend/npm.d.ts +4 -0
  243. package/dist/frontend/npm.js +86 -33
  244. package/dist/frontend/npm.js.map +1 -1
  245. package/dist/frontend/npm.test.js +103 -0
  246. package/dist/frontend/npm.test.js.map +1 -1
  247. package/dist/frontend/pipeline-native.js +2 -1
  248. package/dist/frontend/pipeline-native.js.map +1 -1
  249. package/dist/frontend/program.js +4 -2
  250. package/dist/frontend/program.js.map +1 -1
  251. package/dist/frontend/services-node.js +3 -2
  252. package/dist/frontend/services-node.js.map +1 -1
  253. package/dist/frontend/services.d.ts +5 -1
  254. package/dist/frontend/services.js +9 -1
  255. package/dist/frontend/services.js.map +1 -1
  256. package/dist/frontend/services.test.js +21 -0
  257. package/dist/frontend/services.test.js.map +1 -1
  258. package/dist/frontend/ts7/ast-node.d.ts +2 -0
  259. package/dist/frontend/ts7/ast-node.js +30 -4
  260. package/dist/frontend/ts7/ast-node.js.map +1 -1
  261. package/dist/frontend/ts7/ast-node.test.js +60 -1
  262. package/dist/frontend/ts7/ast-node.test.js.map +1 -1
  263. package/dist/frontend/type-mapper.js +89 -14
  264. package/dist/frontend/type-mapper.js.map +1 -1
  265. package/dist/frontend/union-discriminants.js +22 -7
  266. package/dist/frontend/union-discriminants.js.map +1 -1
  267. package/dist/index.js +19 -12
  268. package/dist/index.js.map +1 -1
  269. package/dist/ir/analysis.js +1 -0
  270. package/dist/ir/analysis.js.map +1 -1
  271. package/dist/ir/integer-loops.d.ts +7 -0
  272. package/dist/ir/integer-loops.js +23 -0
  273. package/dist/ir/integer-loops.js.map +1 -1
  274. package/dist/ir/integer-loops.test.d.ts +1 -0
  275. package/dist/ir/integer-loops.test.js +41 -0
  276. package/dist/ir/integer-loops.test.js.map +1 -0
  277. package/dist/ir/ir.d.ts +44 -26
  278. package/dist/ir/ir.js +69 -11
  279. package/dist/ir/ir.js.map +1 -1
  280. package/dist/ir/ir.test.js +18 -0
  281. package/dist/ir/ir.test.js.map +1 -1
  282. package/dist/ir/serialize.js +21 -1
  283. package/dist/ir/serialize.js.map +1 -1
  284. package/dist/ir/serialize.test.js +21 -0
  285. package/dist/ir/serialize.test.js.map +1 -1
  286. package/dist/ir/traverse.d.ts +0 -3
  287. package/dist/ir/traverse.js +33 -20
  288. package/dist/ir/traverse.js.map +1 -1
  289. package/dist/ir/validate.js +216 -80
  290. package/dist/ir/validate.js.map +1 -1
  291. package/dist/ir/validate.test.js +244 -1
  292. package/dist/ir/validate.test.js.map +1 -1
  293. package/dist/library/compiler-self-identity.js +1 -1
  294. package/dist/library/compiler-self-identity.test.js +2 -2
  295. package/dist/library/compiler-self-identity.test.js.map +1 -1
  296. package/dist/library/fence-eval.js +9 -2
  297. package/dist/library/fence-eval.js.map +1 -1
  298. package/dist/library/fence-eval.test.d.ts +1 -0
  299. package/dist/library/fence-eval.test.js +21 -0
  300. package/dist/library/fence-eval.test.js.map +1 -0
  301. package/dist/library/int-infer.d.ts +2 -2
  302. package/dist/library/int-infer.js +10 -7
  303. package/dist/library/int-infer.js.map +1 -1
  304. package/dist/library/int-infer.test.js +44 -0
  305. package/dist/library/int-infer.test.js.map +1 -1
  306. package/dist/library/prepare.js +2 -1
  307. package/dist/library/prepare.js.map +1 -1
  308. package/dist/native/runtime-typescript.d.ts +4 -0
  309. package/dist/native/runtime-typescript.js +61 -0
  310. package/dist/native/runtime-typescript.js.map +1 -0
  311. package/dist/native/runtime-typescript.test.d.ts +1 -0
  312. package/dist/native/runtime-typescript.test.js +41 -0
  313. package/dist/native/runtime-typescript.test.js.map +1 -0
  314. package/package.json +20 -20
  315. package/surface-manifest.json +385 -29
@@ -1,4 +1,5 @@
1
1
  import { InternalCompilerError } from "../../errors.js";
2
+ import { SYMBOL_T } from "../../ir/ir.js";
2
3
  import { literalValues } from "../literal-values.js";
3
4
  import { literalUnionArm } from "../union-discriminants.js";
4
5
  /* Expression lowering: the expression dispatch (lowerExpr), literals
@@ -10,7 +11,6 @@ import { literalUnionArm } from "../union-discriminants.js";
10
11
  import * as ts from "../ts7/adapter.js";
11
12
  import { dirname } from "node:path";
12
13
  import * as posix from "node:path/posix";
13
- import { pathToFileURL } from "node:url";
14
14
  import { captureContextArguments } from "./function-context.js";
15
15
  import { OBJECT_CALLABLE_VALUES } from "./surfaces.js";
16
16
  import { wasiGuestPath } from "../../wasi-paths.js";
@@ -53,13 +53,15 @@ import { classSymbolKeyOf } from "./symbol-fields.js";
53
53
  import { lowerClassMethodValue } from "./class-method-values.js";
54
54
  import { classInstanceOf } from "./class-dynamic-dispatch.js";
55
55
  import { lowerGlobalValue } from "./lower-global-value.js";
56
- import { lowerClassPrototypeData } from "./class-prototypes.js";
56
+ import { importMetaField, isImportMeta } from "./import-meta.js";
57
+ import { lowerClassPrototypeData, lowerClassPrototypeComputedAssignment } from "./class-prototypes.js";
57
58
  import { isClassCallback } from "./class-callbacks.js";
58
59
  import { builtinPrototypeMethod, lowerArrayIsArrayValue, lowerCheckedPredicateValue, lowerNumberParserValue, lowerObjectAssignValue, lowerStringCodesValue } from "./lower-builtin-values.js";
59
60
  import { lowerArrayFromValue } from "./lower-containers.js";
60
- import { lowerPerfHooksTypeof } from "./lower-builtins.js";
61
+ import { lowerPerfHooksTypeof, lowerUrlAssignment } from "./lower-builtins.js";
61
62
  import { jsBindingHasOpenWrites } from "./lower-stmts.js";
62
63
  import { checkedClassInstanceOf } from "./class-construction.js";
64
+ import { lowerModuleNamespaceElement } from "./module-namespace-elements.js";
63
65
  /** A template piece's RAW text (String.raw's contract: escapes stay
64
66
  * characters). 7's client AST ships no rawText at runtime (the typing
65
67
  * declares it; the serialized node data omits it), so the raw span comes
@@ -123,6 +125,25 @@ function isParseArgsDynProperty(lowerer, expr) {
123
125
  return false;
124
126
  });
125
127
  }
128
+ function isStatFsDynProperty(lowerer, expr) {
129
+ if (!["type", "bsize", "blocks", "bfree", "bavail", "files", "ffree", "bigint"].includes(expr.name.text))
130
+ return false;
131
+ const symbol = lowerer.checker.getSymbolAtLocation(expr.name);
132
+ return !!symbol && lowerer.checker.declarationsOf(symbol).some((declaration) => {
133
+ if (!lowerer.isStdlibFile(declaration.getSourceFile()))
134
+ return false;
135
+ const parent = declaration.parent;
136
+ if (!ts.isInterfaceDeclaration(parent))
137
+ return false;
138
+ if (expr.name.text === "bigint" ? parent.name.text !== "StatFsOptions" : !["StatsFsBase", "StatsFs", "BigIntStatsFs"].includes(parent.name.text))
139
+ return false;
140
+ for (let node = parent.parent; node; node = node.parent) {
141
+ if (ts.isModuleDeclaration(node) && ts.isStringLiteral(node.name))
142
+ return node.name.text === "fs" || node.name.text === "node:fs";
143
+ }
144
+ return false;
145
+ });
146
+ }
126
147
  export function lowerExpr(lowerer, expr) {
127
148
  if (lowerExprDepth >= LOWER_EXPR_MAX_DEPTH) {
128
149
  lowerer.unsupported("SC1090", expr, `expressions nested deeper than ${LOWER_EXPR_MAX_DEPTH} levels`);
@@ -586,6 +607,8 @@ function lowerExprInner(lowerer, expr) {
586
607
  if (ts.isTypeOfExpression(expr)) {
587
608
  if (lowerer.isStdlibGlobal(expr.expression, "process"))
588
609
  return { kind: "strLit", value: "object", type: STRING, loc };
610
+ if (lowerer.isStdlibGlobal(expr.expression, "fetch"))
611
+ return { kind: "strLit", value: "function", type: STRING, loc };
589
612
  const performance = lowerPerfHooksTypeof(lowerer, expr.expression);
590
613
  if (performance)
591
614
  return performance;
@@ -777,7 +800,7 @@ function lowerExprInner(lowerer, expr) {
777
800
  if (use?.kind === "element") {
778
801
  const key = runtimeOptionalElementKey(use.access.argumentExpression);
779
802
  if (key === null) {
780
- lowerer.unsupported("SC1090", use.access, "a computed read from a runtime-optional capture (use a literal key)");
803
+ return varRef(local.id, local.type, loc);
781
804
  }
782
805
  return runtimeOptionalReceiverRead(lowerer, expr, local, key, loc);
783
806
  }
@@ -1067,6 +1090,8 @@ function lowerExprInner(lowerer, expr) {
1067
1090
  }
1068
1091
  if (lowerer.isStdlibGlobal(expr, "ArrayBuffer"))
1069
1092
  return { kind: "libCall", fn: "arrayBuffer.constructor", args: [], type: DYN, loc };
1093
+ if (isJsSourceFile(expr.getSourceFile()) && lowerer.isStdlibGlobal(expr, "Array"))
1094
+ return { kind: "libCall", fn: "dyn.arrayConstructor", args: [], type: DYN, loc };
1070
1095
  if (Object.values(BYTES_ELEMENT_NAME).includes(expr.text) && lowerer.isStdlibSymbol(lowerer.checker.getSymbolAtLocation(expr))) {
1071
1096
  return { kind: "libCall", fn: "bytes.constructor", args: [{ kind: "strLit", value: expr.text, type: STRING, loc }], type: DYN, loc };
1072
1097
  }
@@ -1941,6 +1966,13 @@ function lowerExprInner(lowerer, expr) {
1941
1966
  : { kind: "strIntrinsic", method: "length", receiver: recv, args: [], type: F64, loc };
1942
1967
  }
1943
1968
  }
1969
+ if (isJsSourceFile(expr.getSourceFile()) && expr.name.text === "constructor") {
1970
+ const receiver = tryLowerExpression(lowerer, expr.expression);
1971
+ if (receiver?.type.kind === "dyn" || receiver?.type.kind === "object" && !lowerer.classes.get(receiver.type.className)?.fields.has("constructor")) {
1972
+ return { kind: "dynKeyGet", value: lowerer.coerceToExpected(receiver, DYN),
1973
+ key: { kind: "strLit", value: "constructor", type: STRING, loc }, type: DYN, loc };
1974
+ }
1975
+ }
1944
1976
  // `f.name` / `f.length` / own properties on a FUNCTION-typed JS
1945
1977
  // value (the mustCall wrapper's function-instance members): read
1946
1978
  // through the dyn box — the closure's own-property table answers
@@ -2018,16 +2050,13 @@ function lowerExprInner(lowerer, expr) {
2018
2050
  return nsUndefRead(lowerer, ambientRoot.text, expr, t);
2019
2051
  }
2020
2052
  }
2021
- // parseArgs results/tokens live in the checked-dynamic tree. A token
2022
- // discriminant check narrows its checker type to one anonymous arm,
2023
- // whose ambient property symbols would otherwise hit SC2020 before
2024
- // the generic dyn receiver path below. Provenance is limited to the
2025
- // node:util parseArgs family; every other stdlib member keeps its
2026
- // ordinary surface fence.
2053
+ // Checked-dynamic stdlib results retain ambient property symbols,
2054
+ // including parseArgs tokens narrowed to anonymous union arms. Only
2055
+ // members owned by these implemented families bypass the stdlib fence.
2027
2056
  const segmentDataSymbol = lowerer.typeOf(expr.expression).getSymbol();
2028
2057
  const segmentDataProperty = segmentDataSymbol?.name === "SegmentData" && lowerer.isStdlibSymbol(segmentDataSymbol) &&
2029
2058
  ["segment", "index", "input", "isWordLike"].includes(expr.name.text);
2030
- if (isParseArgsDynProperty(lowerer, expr) || segmentDataProperty) {
2059
+ if (isParseArgsDynProperty(lowerer, expr) || isStatFsDynProperty(lowerer, expr) || segmentDataProperty) {
2031
2060
  const recv = lowerer.lowerExpr(expr.expression);
2032
2061
  if (recv.type.kind === "dyn") {
2033
2062
  const key = {
@@ -2091,7 +2120,8 @@ function lowerExprInner(lowerer, expr) {
2091
2120
  // chain. Scalar-narrowed occurrences bridge via maybeNarrow's
2092
2121
  // validated dynCheck as usual.
2093
2122
  if (recvLowered.type.kind === "dyn" || isJsSourceFile(expr.getSourceFile()) &&
2094
- ["f64", "bool", "bigint", "string", "symbol"].includes(recvLowered.type.kind)) {
2123
+ (["f64", "bool", "bigint", "string", "symbol"].includes(recvLowered.type.kind) ||
2124
+ recvLowered.type.kind === "union" && lowerer.dynConvertible(recvLowered.type))) {
2095
2125
  const key = { kind: "strLit", value: expr.name.text, type: STRING, loc: locOf(expr.name) };
2096
2126
  const opt = hasOptionalChainGuard(expr.expression);
2097
2127
  return lowerer.maybeNarrow({ kind: "dynKeyGet", key, ...(opt ? { optional: true } : {}), value: lowerer.coerceToExpected(recvLowered, DYN), type: DYN, loc }, expr);
@@ -2187,38 +2217,7 @@ function moduleFileName(lowerer, sf) {
2187
2217
  : sf.fileName;
2188
2218
  }
2189
2219
  function importMetaProperty(lowerer, expr) {
2190
- if (!ts.isMetaProperty(expr.expression))
2191
- return null;
2192
- const meta = expr.expression;
2193
- if (meta.keywordToken !== ts.SyntaxKind.ImportKeyword || meta.name.text !== "meta")
2194
- return null;
2195
- const sf = expr.getSourceFile();
2196
- const fileName = moduleFileName(lowerer, sf);
2197
- switch (expr.name.text) {
2198
- case "env":
2199
- return dynUndefinedExpr(locOf(expr));
2200
- case "url":
2201
- return {
2202
- kind: "strLit",
2203
- value: pathToFileURL(fileName, { windows: lowerer.targetPlatform === "win32" }).href,
2204
- type: STRING,
2205
- loc: locOf(expr),
2206
- };
2207
- case "filename":
2208
- return { kind: "strLit", value: fileName, type: STRING, loc: locOf(expr) };
2209
- case "dirname":
2210
- return {
2211
- kind: "strLit",
2212
- value: lowerer.targetPlatform === "wasi" ? posix.dirname(fileName) : dirname(fileName),
2213
- type: STRING,
2214
- loc: locOf(expr),
2215
- };
2216
- case "main":
2217
- return { kind: "boolLit", value: sf === lowerer.entry, type: BOOL, loc: locOf(expr) };
2218
- default:
2219
- lowerer.unsupported("SC1090", expr, `'import.meta.${expr.name.text}' (only url, filename, dirname, and main are supported in static ESM)`);
2220
- return null;
2221
- }
2220
+ return isImportMeta(expr.expression) ? importMetaField(lowerer, expr, expr.name.text) : null;
2222
2221
  }
2223
2222
  /** `c ? a : b`. An explicit destination constructs each branch at that
2224
2223
  * layout before joining it. Without one, retain the expression's inferred
@@ -2540,8 +2539,52 @@ export function maybeNarrow(lowerer, expr, node) {
2540
2539
  // instead of misreading the payload (the dyn boundary's usual stance).
2541
2540
  // Object/array narrowings stay dyn-typed and keep their fences.
2542
2541
  if (expr.type.kind === "dyn") {
2542
+ // An inferred JS member's storage may be deliberately wider than its
2543
+ // declaration (prototype-selected buffers, null-initialized scratch
2544
+ // objects). Extract at the consuming operation, not at the read.
2545
+ if (isJsSourceFile(node.getSourceFile()) && ts.isPropertyAccessExpression(node)) {
2546
+ const receiver = lowerer.mapTypeOf(lowerer.typeOf(node.expression));
2547
+ if (receiver?.kind === "object") {
2548
+ const info = lowerer.classes.get(receiver.className);
2549
+ if (info?.fields.get(node.name.text)?.kind === "dyn" || lowerer.findMethodOn(info ?? null, `get:${node.name.text}`)?.sig.ret.kind === "dyn")
2550
+ return expr;
2551
+ }
2552
+ if (receiver?.kind === "classval") {
2553
+ const info = lowerer.classes.get(receiver.className);
2554
+ if (info && hasRuntimeStatics(info))
2555
+ return expr;
2556
+ }
2557
+ }
2558
+ if (isJsSourceFile(node.getSourceFile()) &&
2559
+ (ts.isPropertyAccessExpression(node) || ts.isElementAccessExpression(node))) {
2560
+ let receiver = node.expression;
2561
+ while (ts.isPropertyAccessExpression(receiver) || ts.isElementAccessExpression(receiver) || ts.isParenthesizedExpression(receiver)) {
2562
+ if (ts.isPropertyAccessExpression(receiver)) {
2563
+ const owner = lowerer.mapTypeOf(lowerer.typeOf(receiver.expression));
2564
+ if (owner?.kind === "object" && lowerer.classes.get(owner.className)?.fields.get(receiver.name.text)?.kind === "dyn")
2565
+ return expr;
2566
+ }
2567
+ receiver = receiver.expression;
2568
+ }
2569
+ if (receiver.kind === ts.SyntaxKind.ThisKeyword && lowerer.resolveThis()?.type.kind === "dyn")
2570
+ return expr;
2571
+ if (ts.isIdentifier(receiver)) {
2572
+ const stored = lowerer.peekLocal(receiver)?.type ?? lowerer.globalOf(receiver)?.type;
2573
+ if (stored?.kind === "dyn")
2574
+ return expr;
2575
+ const symbol = lowerer.resolveValueSymbol(receiver);
2576
+ const bound = symbol && lowerer.implicitParamTypes?.get(symbol);
2577
+ if (bound && lowerer.mapTypeOf(bound)?.kind === "dyn")
2578
+ return expr;
2579
+ }
2580
+ }
2543
2581
  if (isJsSourceFile(node.getSourceFile()) && ts.isIdentifier(node)) {
2544
2582
  const symbol = lowerer.resolveValueSymbol(node);
2583
+ if (symbol && lowerer.checker.declarationsOf(symbol).some((decl) => ts.isParameter(decl) &&
2584
+ ts.isMethodDeclaration(decl.parent) && lowerer.checkedVirtualJsMethods.has(decl.parent)))
2585
+ return expr;
2586
+ if (symbol && lowerer.checker.declarationsOf(symbol).some((decl) => ts.isParameter(decl) && ts.isConstructorDeclaration(decl.parent)))
2587
+ return expr;
2545
2588
  if (symbol && lowerer.checker.declarationsOf(symbol).some((decl) => ts.isVariableDeclaration(decl) && jsBindingHasOpenWrites(lowerer, decl)))
2546
2589
  return expr;
2547
2590
  if (symbol && lowerer.checker.declarationsOf(symbol).some((decl) => ts.isParameter(decl) && decl.initializer && !decl.type &&
@@ -2605,6 +2648,19 @@ export function maybeNarrow(lowerer, expr, node) {
2605
2648
  }
2606
2649
  if (expr.type.kind !== "union")
2607
2650
  return expr;
2651
+ // Represented fields and index values can include undefined even when
2652
+ // checker inference or lib.d.ts declares strings (RegExp captures).
2653
+ // Only a declaration that represents the optional arm can provide a
2654
+ // trustworthy flow narrowing; otherwise consumers must check it.
2655
+ if ((expr.kind === "recordGet" || expr.kind === "recordKeyGet") &&
2656
+ (ts.isPropertyAccessExpression(node) || ts.isElementAccessExpression(node))) {
2657
+ const receiver = lowerer.mapTypeOf(lowerer.typeOf(node.expression));
2658
+ const shape = receiver?.kind === "record" ? lowerer.shapes.get(receiver.shapeId) : undefined;
2659
+ const declared = expr.kind === "recordGet" ? shape?.fields.find((field) => field.name === expr.field)?.type : shape?.indexValue;
2660
+ if (lowerer.armTag(expr.type.unionId, UNDEFINED_T) >= 0 &&
2661
+ declared && !(declared.kind === "union" && lowerer.armTag(declared.unionId, UNDEFINED_T) >= 0))
2662
+ return expr;
2663
+ }
2608
2664
  if (ts.isIdentifier(node)) {
2609
2665
  const symbol = lowerer.resolveValueSymbol(node);
2610
2666
  if (symbol && lowerer.unstableSwitchBindings.has(symbol))
@@ -3559,14 +3615,16 @@ export function lowerIntrinsicProperty(lowerer, expr) {
3559
3615
  if (receiver.type.kind === "dyn")
3560
3616
  return { kind: "dynKeyGet", value: receiver,
3561
3617
  key: { kind: "strLit", value: name, type: STRING, loc: locOf(expr) }, type: DYN, loc: locOf(expr) };
3562
- // Ordinary arrays keep the existing Array builtin identity token.
3563
- const result = { kind: "strLit", value: "[builtin Array]", type: STRING, loc: locOf(expr) };
3564
- return { kind: "seqExpr", stmts: [{ kind: "exprStmt", expr: receiver, loc: locOf(expr) }], result, type: STRING, loc: locOf(expr) };
3618
+ const result = { kind: "libCall", fn: "dyn.arrayConstructor", args: [], type: DYN, loc: locOf(expr) };
3619
+ return { kind: "seqExpr", stmts: [{ kind: "exprStmt", expr: receiver, loc: locOf(expr) }], result, type: DYN, loc: locOf(expr) };
3565
3620
  }
3566
3621
  const strictReceiver = (expected) => {
3567
3622
  const value = lowerer.lowerExpr(expr.expression);
3568
- if (value.type.kind === "dyn")
3623
+ if (value.type.kind === "dyn") {
3624
+ if (isJsSourceFile(expr.getSourceFile()) && name === "length")
3625
+ return value;
3569
3626
  return lowerer.coerceInto(expr.expression, value, expected);
3627
+ }
3570
3628
  return lowerer.runtimeOptionalPropertyReceiver(expr.expression, value, expected, name) ?? value;
3571
3629
  };
3572
3630
  if (kind === "child") {
@@ -3670,7 +3728,7 @@ export function lowerIntrinsicProperty(lowerer, expr) {
3670
3728
  // (the child.stdout pattern); a checker-narrowed read extracts
3671
3729
  // through maybeNarrow like any union member.
3672
3730
  if (name === "description") {
3673
- const receiver = lowerer.lowerExpr(expr.expression);
3731
+ const receiver = lowerer.coerceToExpected(lowerer.lowerExpr(expr.expression), SYMBOL_T);
3674
3732
  const type = { kind: "union", unionId: lowerer.unions.intern([STRING, UNDEFINED_T]) };
3675
3733
  return { kind: "libCall", fn: "sym.desc", args: [receiver], type, loc };
3676
3734
  }
@@ -3771,6 +3829,9 @@ export function lowerIntrinsicProperty(lowerer, expr) {
3771
3829
  let receiver = expected?.kind === "bytes"
3772
3830
  ? strictReceiver(expected)
3773
3831
  : lowerer.lowerExpr(expr.expression);
3832
+ if (receiver.type.kind === "dyn")
3833
+ return { kind: "dynCheck", value: { kind: "dynKeyGet", value: receiver,
3834
+ key: { kind: "strLit", value: name, type: STRING, loc: locOf(expr) }, type: DYN, loc: locOf(expr) }, type: F64, loc: locOf(expr) };
3774
3835
  if (receiver.type.kind === "union" && lowerer.armTag(receiver.type.unionId, UNDEFINED_T) >= 0) {
3775
3836
  const present = lowerer.stripUndefinedArm(receiver.type);
3776
3837
  const helper = present.kind === "bytes"
@@ -4020,6 +4081,8 @@ export function lowerArrayLiteral(lowerer, expr, expected) {
4020
4081
  if (arms?.length && arms.every((arm) => arm.kind === "classval"))
4021
4082
  mapped = DYN;
4022
4083
  }
4084
+ if (!expected && isJsSourceFile(expr.getSourceFile()) && expr.elements.some((element) => ts.isSpreadElement(element) && tryLowerExpression(lowerer, element.expression)?.type.kind === "dyn"))
4085
+ mapped = DYN;
4023
4086
  // An EMPTY literal under a CONST ASSERTION whose type queries panicked
4024
4087
  // (tsgo's readonly-[] TupleType conversion — the facade answers `any`,
4025
4088
  // which maps to nothing statically and to an island value under
@@ -4417,6 +4480,12 @@ export function lowerOptionalNumber(lowerer, operand, loc, narrowedNode) {
4417
4480
  * string-key element access (`a["length"]`) and string indexing (`s[0]`
4418
4481
  * typechecks against the lib's index signature; use .charAt) stay out. */
4419
4482
  export function lowerElementAccess(lowerer, expr) {
4483
+ if (isImportMeta(expr.expression)) {
4484
+ const name = lowerer.foldedStringKeyOf(expr.argumentExpression);
4485
+ if (name === null)
4486
+ lowerer.unsupported("SC1090", expr, "import.meta with a runtime-computed key (use a statically-known metadata field)");
4487
+ return importMetaField(lowerer, expr, name);
4488
+ }
4420
4489
  // `a?.[i]`: the guard lowers as an optional-chain step around the
4421
4490
  // plain element read below.
4422
4491
  if (expr.questionDotToken && !lowerer.chainHandled.has(expr)) {
@@ -4438,6 +4507,9 @@ export function lowerElementAccess(lowerer, expr) {
4438
4507
  const cachedModule = lowerRequireCacheElement(lowerer, expr);
4439
4508
  if (cachedModule)
4440
4509
  return cachedModule;
4510
+ const namespaceElement = lowerModuleNamespaceElement(lowerer, expr);
4511
+ if (namespaceElement)
4512
+ return namespaceElement;
4441
4513
  // Native Web handles use the same supported surface for bracket and dot
4442
4514
  // spellings. Fence a statically-known unsupported key before the generic
4443
4515
  // checked-dynamic element-read path can turn it into a runtime missing
@@ -4540,6 +4612,13 @@ export function lowerElementAccess(lowerer, expr) {
4540
4612
  const key = lowerer.lowerExprExpecting(expr.argumentExpression, DYN);
4541
4613
  return lowerer.maybeNarrow({ kind: "dynKeyGet", key, value: boxed, type: DYN, loc }, expr);
4542
4614
  }
4615
+ if (receiver?.type.kind === "array" || receiver?.type.kind === "bytes")
4616
+ receiverIr = receiver.type;
4617
+ if (receiver?.type.kind === "union") {
4618
+ const present = lowerer.stripUndefinedArm(receiver.type);
4619
+ if (present.kind === "array" || present.kind === "bytes")
4620
+ receiverIr = present;
4621
+ }
4543
4622
  }
4544
4623
  // A readonly tuple union under Array.isArray is checker-typed as an
4545
4624
  // intersection with any[], whose structural mapping is not the tuple
@@ -4774,6 +4853,11 @@ export function lowerElementAccess(lowerer, expr) {
4774
4853
  if (receiverIr?.kind !== "array") {
4775
4854
  {
4776
4855
  const receiver = tryLowerExpression(lowerer, expr.expression);
4856
+ if (receiver?.type.kind === "dyn" || receiver && isJsSourceFile(expr.getSourceFile()) &&
4857
+ (receiver.type.kind === "union" || receiver.type.kind === "bytes") && lowerer.dynConvertible(receiver.type)) {
4858
+ const key = lowerRecordPropertyKey(lowerer, lowerer.lowerExpr(expr.argumentExpression), expr.argumentExpression);
4859
+ return lowerer.maybeNarrow({ kind: "dynKeyGet", value: lowerer.coerceInto(expr.expression, receiver, DYN), key, type: DYN, loc: locOf(expr) }, expr);
4860
+ }
4777
4861
  if (receiver?.type.kind === "func" &&
4778
4862
  canBoxFuncIntoDyn(receiver.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
4779
4863
  const key = lowerRecordPropertyKey(lowerer, lowerer.lowerExpr(expr.argumentExpression), expr.argumentExpression);
@@ -5353,7 +5437,9 @@ export function lowerElementCompound(lowerer, expr, op) {
5353
5437
  const oldLocal = lowerer.declareHiddenLocal("%compoundOld", oldValue.type);
5354
5438
  const oldRef = () => varRef(oldLocal.id, oldValue.type, loc);
5355
5439
  const rhs = lowerer.lowerExpr(expr.right);
5356
- const numericRhs = lowerOptionalNumber(lowerer, rhs, loc);
5440
+ const numericRhs = rhs.type.kind === "dyn" && isJsSourceFile(expr.getSourceFile()) && receiver.type.kind === "bytes"
5441
+ ? { kind: "libCall", fn: "dyn.toNumberCoerce", args: [rhs], type: F64, loc }
5442
+ : lowerOptionalNumber(lowerer, rhs, loc);
5357
5443
  const elementType = receiver.type.kind === "array" ? receiver.type.elem : F64;
5358
5444
  const valueType = elementType.kind === "union" && lowerer.armTag(elementType.unionId, UNDEFINED_T) >= 0
5359
5445
  ? lowerer.stripUndefinedArm(elementType)
@@ -5432,6 +5518,18 @@ export function lowerNativeFunctionAssignment(lowerer, expr) {
5432
5518
  (!ts.isPropertyAccessExpression(target) && !ts.isElementAccessExpression(target)) ||
5433
5519
  target.questionDotToken)
5434
5520
  return null;
5521
+ // Checked constructors share the callable's live property descriptors.
5522
+ const classType = storedClassValueType(lowerer, target.expression);
5523
+ const staticClass = classType?.kind === "classval" ? lowerer.classes.get(classType.className) : undefined;
5524
+ if (staticClass && hasRuntimeStatics(staticClass)) {
5525
+ return lowerDynMemberAssignment(lowerer, expr, lowerer.lowerExprExpecting(target.expression, DYN));
5526
+ }
5527
+ // Other class statics and prototype tables have their own paths.
5528
+ // Probing them as ordinary functions could materialize unused methods.
5529
+ if (lowerer.exactClassOfReceiver(target.expression) ||
5530
+ ts.isPropertyAccessExpression(target.expression) && target.expression.name.text === "prototype" &&
5531
+ lowerer.exactClassOfReceiver(target.expression.expression))
5532
+ return null;
5435
5533
  const receiver = tryLowerExpression(lowerer, target.expression);
5436
5534
  if (receiver?.type.kind !== "func" ||
5437
5535
  !canBoxFuncIntoDyn(receiver.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id)))
@@ -5445,6 +5543,9 @@ export function lowerNativeFunctionAssignment(lowerer, expr) {
5445
5543
  return lowerDynMemberAssignment(lowerer, expr, boxed);
5446
5544
  }
5447
5545
  export function lowerElementWrite(lowerer, expr) {
5546
+ const prototype = lowerClassPrototypeComputedAssignment(lowerer, expr);
5547
+ if (prototype)
5548
+ return { kind: "exprStmt", expr: prototype, loc: locOf(expr) };
5448
5549
  const target = expr.left;
5449
5550
  fenceNodeModuleMutation(lowerer, target, "assignment");
5450
5551
  const globalKey = globalSymbolKey(lowerer, target.expression, target.argumentExpression);
@@ -5502,6 +5603,12 @@ export function lowerElementWrite(lowerer, expr) {
5502
5603
  }
5503
5604
  }
5504
5605
  let receiverIr = lowerer.mapTypeOf(lowerer.typeOf(target.expression));
5606
+ if (isJsSourceFile(expr.getSourceFile()) && checkedReceiver) {
5607
+ const represented = checkedReceiver.type.kind === "union"
5608
+ ? lowerer.stripUndefinedArm(checkedReceiver.type) : checkedReceiver.type;
5609
+ if (represented.kind === "array" || represented.kind === "bytes")
5610
+ receiverIr = represented;
5611
+ }
5505
5612
  if (receiverIr === null || receiverIr.kind === "dyn") {
5506
5613
  const receiver = tryLowerExpression(lowerer, target.expression);
5507
5614
  if (receiver?.type.kind === "array")
@@ -6278,78 +6385,86 @@ export function lowerPrefixUnary(lowerer, expr) {
6278
6385
  }
6279
6386
  lowerer.unsupported("SC1090", expr, `syntax '${ts.syntaxKindName(expr.kind)}'`);
6280
6387
  }
6281
- /** `x++`/`x--`/`++x`/`--x` in EXPRESSION position — the incDec node:
6282
- * read, write ±1, yield old (postfix) or new (prefix) value. Receivers
6283
- * are f64 LOCALS or module globals (captured/boxed included — the
6284
- * backend reads/writes through the box); record fields and array
6285
- * elements keep the fence in value position (statement-position `obj.f++`
6286
- * still desugars through the compound-field path). */
6287
- function lowerIncDec(lowerer, expr, prefix) {
6388
+ /** Member updates evaluate the reference once, convert its old value with
6389
+ * ToNumeric, store the new value, then yield the old or new numeric value. */
6390
+ export function lowerIncDec(lowerer, expr, prefix) {
6288
6391
  const loc = locOf(expr);
6289
6392
  const op = expr.operator === ts.SyntaxKind.PlusPlusToken ? "+" : "-";
6290
6393
  if (!ts.isIdentifier(expr.operand)) {
6291
- if (ts.isPropertyAccessExpression(expr.operand)) {
6292
- const target = staticFieldWriteTarget(lowerer, expr.operand);
6394
+ const access = expr.operand;
6395
+ if (!ts.isPropertyAccessExpression(access) && !ts.isElementAccessExpression(access) || access.questionDotToken) {
6396
+ lowerer.unsupported("SC1045", expr, "increment/decrement of this target");
6397
+ }
6398
+ fenceNodeModuleMutation(lowerer, access, "assignment");
6399
+ if (ts.isPropertyAccessExpression(access)) {
6400
+ const target = staticFieldWriteTarget(lowerer, access);
6293
6401
  if (target) {
6294
6402
  if (target.type.kind !== "f64")
6295
6403
  lowerer.unsupported("SC1043", expr);
6296
6404
  return { kind: "incDec", op, prefix, localId: target.id, type: F64, loc };
6297
6405
  }
6298
6406
  }
6299
- // CLASS-FIELD receivers (`if (--this.limit === 0)` — countdown.js's
6300
- // dec(); `--this[kLimit]` — its symbol-keyed spelling): a single-
6301
- // evaluation read-modify-write over the instance, yielding old/new
6302
- // like the local form. f64 fields are JS-exact; CHECKED-DYNAMIC
6303
- // fields (implicit-any ctor assignments in JS) take the dyn
6304
- // arithmetic stance — the number validates out (dynCheck's
6305
- // catchable TypeError, never a silent ToNumber; SEMANTICS.md),
6306
- // computes, and boxes back. Array elements, record fields, and
6307
- // accessor-backed names keep the fence.
6308
- if ((ts.isPropertyAccessExpression(expr.operand) || ts.isElementAccessExpression(expr.operand)) &&
6309
- !expr.operand.questionDotToken) {
6310
- if (ts.isPropertyAccessExpression(expr.operand) && isJsSourceFile(expr.getSourceFile())) {
6311
- const receiver = lowerer.lowerExpr(expr.operand.expression);
6312
- if (receiver.type.kind === "dyn") {
6313
- const local = lowerer.declareHiddenLocal("%incrementReceiver", DYN);
6314
- const old = lowerer.declareHiddenLocal("%incrementOld", DYN);
6315
- const next = lowerer.declareHiddenLocal("%incrementNext", DYN);
6316
- const value = varRef(local.id, DYN, loc);
6317
- const key = { kind: "strLit", value: expr.operand.name.text, type: STRING, loc };
6318
- return { kind: "seqExpr", stmts: [
6319
- { kind: "varDecl", localId: local.id, init: receiver, loc },
6320
- { kind: "varDecl", localId: old.id, init: { kind: "libCall", fn: "dyn.toNumeric", args: [
6321
- { kind: "dynKeyGet", value, key, type: DYN, loc },
6322
- ], type: DYN, loc }, loc },
6323
- { kind: "varDecl", localId: next.id, init: { kind: "libCall", fn: "dyn.increment", args: [varRef(old.id, DYN, loc),
6324
- { kind: "boolLit", value: op === "+", type: BOOL, loc }], type: DYN, loc }, loc },
6325
- { kind: "exprStmt", expr: { kind: "libCall", fn: "dyn.keySet", args: [value, key, varRef(next.id, DYN, loc)], type: VOID, loc }, loc },
6326
- ], result: varRef(prefix ? next.id : old.id, DYN, loc), type: DYN, loc };
6327
- }
6328
- }
6329
- const target = ts.isPropertyAccessExpression(expr.operand)
6330
- ? lowerer.fieldTarget(expr.operand)
6331
- : symbolFieldTarget(lowerer, expr.operand);
6332
- if (target?.container === "class" &&
6333
- !RUNTIME_ERROR_CLASSES.has(target.className) &&
6334
- (target.fieldType.kind === "f64" ||
6335
- (target.fieldType.kind === "dyn" && isJsSourceFile(expr.getSourceFile())))) {
6336
- return {
6337
- kind: "fieldIncDec",
6338
- op,
6339
- prefix,
6340
- obj: target.obj,
6341
- className: target.className,
6342
- field: target.field,
6343
- fieldDyn: target.fieldType.kind === "dyn",
6344
- type: F64,
6345
- loc,
6346
- };
6347
- }
6348
- }
6349
- // Other field/element receivers need a read-modify-write over a
6350
- // computed receiver — statement position has that desugar; value
6351
- // position does not yet. The message names the working forms.
6352
- lowerer.unsupported("SC1045", expr, "increment/decrement of record fields or elements in expression position");
6407
+ const stmts = [];
6408
+ const save = (value, name) => {
6409
+ const local = lowerer.declareHiddenLocal(name, value.type);
6410
+ stmts.push({ kind: "varDecl", localId: local.id, init: value, loc });
6411
+ return varRef(local.id, value.type, loc);
6412
+ };
6413
+ const finish = (read, write) => {
6414
+ const old = save(read.type.kind === "f64" ? read : {
6415
+ kind: "libCall", fn: "dyn.toNumeric", args: [lowerer.coerceInto(access, read, DYN)], type: DYN, loc,
6416
+ }, "%incrementOld");
6417
+ const next = save(old.type.kind === "f64" ? {
6418
+ kind: "bin", op, left: old, right: { kind: "numLit", value: 1, type: F64, loc }, type: F64, loc,
6419
+ } : {
6420
+ kind: "libCall", fn: "dyn.increment", args: [old, { kind: "boolLit", value: op === "+", type: BOOL, loc }], type: DYN, loc,
6421
+ }, "%incrementNext");
6422
+ stmts.push(write(next));
6423
+ const result = prefix ? next : old;
6424
+ return { kind: "seqExpr", stmts, result, type: result.type, loc };
6425
+ };
6426
+ const raw = lowerer.lowerExpr(access.expression);
6427
+ // Keep native array/byte storage: boxing a native array can create a
6428
+ // checked view, which is not a substitute for updating its slot.
6429
+ if (ts.isElementAccessExpression(access) && (raw.type.kind === "array" || raw.type.kind === "bytes")) {
6430
+ const receiver = save(raw, "%incrementArray");
6431
+ const rawIndex = lowerer.lowerExpr(access.argumentExpression);
6432
+ const index = save(rawIndex.type.kind === "dyn" && isJsSourceFile(expr.getSourceFile())
6433
+ ? { kind: "libCall", fn: "dyn.toNumberCoerce", args: [rawIndex], type: F64, loc } : rawIndex, "%incrementIndex");
6434
+ if (index.type.kind !== "f64")
6435
+ lowerer.unsupported("SC1090", access, "incrementing non-number array keys");
6436
+ const type = raw.type;
6437
+ const read = type.kind === "array"
6438
+ ? arrayValueRead(lowerer, receiver, index, type.elem, loc)
6439
+ : { kind: "bytesIntrinsic", method: "get", receiver, args: [index], type: F64, loc };
6440
+ return finish(read, (value) => type.kind === "array"
6441
+ ? arrayValueStore(lowerer, receiver, index, lowerer.coerceInto(access, value, type.elem), type.elem, loc)
6442
+ : { kind: "bytesSet", arr: receiver, index, value: lowerer.coerceInto(access, value, F64), loc });
6443
+ }
6444
+ if (isJsSourceFile(expr.getSourceFile()) && raw.type.kind === "dyn") {
6445
+ const receiver = save(raw, "%incrementReceiver");
6446
+ const key = save(ts.isElementAccessExpression(access)
6447
+ ? lowerer.lowerExprExpecting(access.argumentExpression, DYN)
6448
+ : lowerer.coerceInto(access, { kind: "strLit", value: access.name.text, type: STRING, loc }, DYN), "%incrementKey");
6449
+ return finish({ kind: "dynKeyGet", value: receiver, key, type: DYN, loc }, (value) => ({
6450
+ kind: "exprStmt", expr: { kind: "libCall", fn: "dyn.keySetComputed", args: [receiver, key, lowerer.coerceInto(access, value, DYN)], type: VOID, loc }, loc,
6451
+ }));
6452
+ }
6453
+ const target = ts.isPropertyAccessExpression(access) ? lowerer.fieldTarget(access) : symbolFieldTarget(lowerer, access);
6454
+ if (target && lowerer.dynConvertible(target.fieldType)) {
6455
+ target.obj = save(target.obj, "%incrementReceiver");
6456
+ return finish(lowerer.fieldGetExpr(target, loc, access), (value) => lowerer.fieldSetStmt(target, lowerer.coerceInto(access, value, target.fieldType), loc, access));
6457
+ }
6458
+ if (isJsSourceFile(expr.getSourceFile()) && lowerer.dynConvertible(raw.type)) {
6459
+ const receiver = save(lowerer.coerceInto(access.expression, raw, DYN), "%incrementReceiver");
6460
+ const key = save(ts.isElementAccessExpression(access)
6461
+ ? lowerer.lowerExprExpecting(access.argumentExpression, DYN)
6462
+ : lowerer.coerceInto(access, { kind: "strLit", value: access.name.text, type: STRING, loc }, DYN), "%incrementKey");
6463
+ return finish({ kind: "dynKeyGet", value: receiver, key, type: DYN, loc }, (value) => ({
6464
+ kind: "exprStmt", expr: { kind: "libCall", fn: "dyn.keySetComputed", args: [receiver, key, lowerer.coerceInto(access, value, DYN)], type: VOID, loc }, loc,
6465
+ }));
6466
+ }
6467
+ lowerer.unsupported("SC1045", expr, "increment/decrement of this member target");
6353
6468
  }
6354
6469
  const target = lowerer.resolveWritable(expr.operand);
6355
6470
  if (!target) {
@@ -6429,6 +6544,7 @@ export function lowerCompoundValueToTarget(lowerer, expr, compound, target) {
6429
6544
  const loc = locOf(expr);
6430
6545
  const read = { kind: "varRef", localId: target.id, type: target.type, loc: locOf(expr.left) };
6431
6546
  const rhs = lowerer.lowerExpr(expr.right);
6547
+ const numericRead = lowerOptionalNumber(lowerer, read, loc);
6432
6548
  const numericRhs = lowerOptionalNumber(lowerer, rhs, loc);
6433
6549
  if (target.type.kind === "jsval" || rhs.type.kind === "jsval") {
6434
6550
  const JS_COMPOUND = { "+": "add", "-": "sub", "*": "mul", "/": "div", "%": "mod", "**": "pow" };
@@ -6445,8 +6561,8 @@ export function lowerCompoundValueToTarget(lowerer, expr, compound, target) {
6445
6561
  if (compound === "+" && target.type.kind === "string") {
6446
6562
  return { kind: "strConcat", left: read, right: lowerer.ensureString(rhs, expr.right), type: STRING, loc };
6447
6563
  }
6448
- if (target.type.kind === "f64" && numericRhs.type.kind === "f64") {
6449
- return { kind: "bin", op: compound, left: read, right: numericRhs, type: F64, loc };
6564
+ if (numericRead.type.kind === "f64" && numericRhs.type.kind === "f64") {
6565
+ return lowerer.coerceInto(expr, { kind: "bin", op: compound, left: numericRead, right: numericRhs, type: F64, loc }, target.type);
6450
6566
  }
6451
6567
  if ((target.type.kind === "dyn" || rhs.type.kind === "dyn") &&
6452
6568
  isJsSourceFile(expr.getSourceFile())) {
@@ -6466,7 +6582,13 @@ export function lowerBinary(lowerer, expr) {
6466
6582
  if (cacheHas)
6467
6583
  return cacheHas;
6468
6584
  if (op === ts.SyntaxKind.EqualsToken || (op >= ts.SyntaxKind.FirstCompoundAssignment && op <= ts.SyntaxKind.LastCompoundAssignment)) {
6585
+ const urlWrite = lowerUrlAssignment(lowerer, expr);
6586
+ if (urlWrite)
6587
+ return urlWrite;
6469
6588
  if (op === ts.SyntaxKind.EqualsToken) {
6589
+ const prototypeWrite = lowerClassPrototypeComputedAssignment(lowerer, expr);
6590
+ if (prototypeWrite)
6591
+ return prototypeWrite;
6470
6592
  const callableWrite = lowerNativeFunctionAssignment(lowerer, expr);
6471
6593
  if (callableWrite)
6472
6594
  return callableWrite;
@@ -6731,8 +6853,14 @@ export function lowerBinary(lowerer, expr) {
6731
6853
  }
6732
6854
  const strictEquality = op === ts.SyntaxKind.EqualsEqualsEqualsToken ||
6733
6855
  op === ts.SyntaxKind.ExclamationEqualsEqualsToken;
6734
- const left = strictEquality ? lowerAbsenceProbe(lowerer, expr.left) ?? lowerer.lowerExpr(expr.left) : lowerer.lowerExpr(expr.left);
6735
- const right = strictEquality ? lowerAbsenceProbe(lowerer, expr.right) ?? lowerer.lowerExpr(expr.right) : lowerer.lowerExpr(expr.right);
6856
+ let left = strictEquality ? lowerAbsenceProbe(lowerer, expr.left) ?? lowerer.lowerExpr(expr.left) : lowerer.lowerExpr(expr.left);
6857
+ let right = strictEquality ? lowerAbsenceProbe(lowerer, expr.right) ?? lowerer.lowerExpr(expr.right) : lowerer.lowerExpr(expr.right);
6858
+ if (strictEquality && (left.type.kind === "caught" || right.type.kind === "caught")) {
6859
+ if (left.type.kind === "caught")
6860
+ left = { kind: "caughtToDyn", value: left, type: DYN, loc: left.loc };
6861
+ if (right.type.kind === "caught")
6862
+ right = { kind: "caughtToDyn", value: right, type: DYN, loc: right.loc };
6863
+ }
6736
6864
  if (left.type.kind === "dyn" || right.type.kind === "dyn") {
6737
6865
  // The narrowing unit comparisons ARE answerable on unknown: `v ===
6738
6866
  // undefined` / `v !== null` test the dyn node's kind directly, and
@@ -6760,7 +6888,7 @@ export function lowerBinary(lowerer, expr) {
6760
6888
  const dynSide = left.type.kind === "dyn" ? left : right;
6761
6889
  const scalarSide = dynSide === left ? right : left;
6762
6890
  const reference = scalarSide.type;
6763
- if ((isDynTypedRefType(reference) || reference.kind === "record" || reference.kind === "array" ||
6891
+ if ((reference.kind === "object" || reference.kind === "record" || reference.kind === "array" ||
6764
6892
  reference.kind === "bytes" || reference.kind === "func" || reference.kind === "classval" || reference.kind === "regex" || reference.kind === "url" ||
6765
6893
  reference.kind === "bigint" || reference.kind === "symbol" || reference.kind === "map" || reference.kind === "set" || reference.kind === "union" || DYN_HANDLE_KINDS.has(reference.kind)) &&
6766
6894
  lowerer.dynConvertible(reference)) {
@@ -7976,6 +8104,8 @@ function lowerDynTypeofTest(lowerer, expr, loc) {
7976
8104
  for (const [a, b] of operandPairs(expr)) {
7977
8105
  if (!ts.isTypeOfExpression(a))
7978
8106
  continue;
8107
+ if (lowerer.isStdlibGlobal(a.expression, "fetch"))
8108
+ continue;
7979
8109
  // Non-literal comparisons use the ordinary typeof string value,
7980
8110
  // preserving both operands' evaluation order without a narrowing test.
7981
8111
  if (!ts.isStringLiteral(b))
@@ -9338,11 +9468,10 @@ function matchAllRegexOf(lowerer, e) {
9338
9468
  * member fence);
9339
9469
  * - a nullable receiver (the JS `s.match(re).groups` idiom) throws
9340
9470
  * Node's exact TypeError on the unit arms;
9341
- * - every declared name is a key (nonparticipating groups hold "" —
9342
- * divergence 51's rule, exactly the slice elements they project);
9471
+ * - every declared name is a key (nonparticipating groups hold undefined,
9472
+ * exactly the slice elements they project);
9343
9473
  * - ES2025 duplicate names (distinct alternatives) project the first
9344
- * participating occurrence: at most one participates, and a
9345
- * participating-empty "" falls through to slots that are "" anyway;
9474
+ * participating occurrence, including a participating empty string;
9346
9475
  * - key order is group declaration order (declaredOrder), Node's own.
9347
9476
  * The record has no prototype — Node's groups object is null-prototype,
9348
9477
  * observable only through util.inspect's "[Object: null prototype]"
@@ -9419,12 +9548,8 @@ function matchSliceUnionArms(lowerer, unionId) {
9419
9548
  }
9420
9549
  return { arrTag, units };
9421
9550
  }
9422
- /** The groups-record projection call: the result is the CHECKER'S OWN
9423
- * shape — `{ [key: string]: string }`, the hybrid index-signature
9424
- * record with no declared fields — holding one OVERFLOW entry per
9425
- * group name in declaration order, so every downstream consumer
9426
- * (recordKeyGet reads, Object.keys, JSON, the `| undefined` union
9427
- * wrap) meets exactly the type tsc reported. One lifted helper per
9551
+ /** The groups-record projection holds string | undefined values, including
9552
+ * an own overflow entry for every nonparticipating capture. One lifted helper per
9428
9553
  * (index list, receiver representation) builds it; see
9429
9554
  * lowerMatchGroupsRead for the semantics the body encodes. */
9430
9555
  export function lowerGroupsProjection(lowerer, recv, groups, loc) {
@@ -9442,7 +9567,8 @@ export function lowerGroupsProjection(lowerer, recv, groups, loc) {
9442
9567
  order.push(g.name);
9443
9568
  }
9444
9569
  }
9445
- const shapeId = lowerer.shapes.intern([], false, STRING);
9570
+ const valueType = arrayValueType(lowerer, STRING);
9571
+ const shapeId = lowerer.shapes.intern([], false, valueType);
9446
9572
  const recordT = { kind: "record", shapeId };
9447
9573
  const recvKey = recv.type.kind === "union" ? recv.type.unionId : "arr";
9448
9574
  const key = `regexgroups:${shapeId}:${groups.map((g) => `${g.name}=${g.index}`).join(",")}:${recvKey}`;
@@ -9484,7 +9610,7 @@ export function lowerGroupsProjection(lowerer, recv, groups, loc) {
9484
9610
  body.push({ kind: "varDecl", localId: "arr.0", init: narrowed, loc });
9485
9611
  mRef = { kind: "varRef", localId: "arr.0", type: arrayOf(STRING), loc };
9486
9612
  }
9487
- const elem = (index) => ({ kind: "arrayGet", arr: mRef, index: numLit(index, loc), type: STRING, loc });
9613
+ const elem = (index) => arrayValueRead(lowerer, mRef, numLit(index, loc), STRING, loc);
9488
9614
  const values = new Map();
9489
9615
  order.forEach((name, i) => {
9490
9616
  const idxs = indicesByName.get(name);
@@ -9492,16 +9618,16 @@ export function lowerGroupsProjection(lowerer, recv, groups, loc) {
9492
9618
  values.set(name, elem(idxs[0]));
9493
9619
  return;
9494
9620
  }
9495
- // Duplicates: the first non-"" occurrence (at most one
9496
- // participates; all-"" answers "" like any nonparticipating slot).
9621
+ // Duplicates: the first participating occurrence. Empty strings
9622
+ // participate; undefined means this alternative did not match.
9497
9623
  const id = `g${i}.0`;
9498
- locals.push({ id, name: `g${i}`, type: STRING, mutable: true });
9624
+ locals.push({ id, name: `g${i}`, type: valueType, mutable: true });
9499
9625
  body.push({ kind: "varDecl", localId: id, init: elem(idxs[0]), loc });
9500
- const gRef = { kind: "varRef", localId: id, type: STRING, loc };
9626
+ const gRef = { kind: "varRef", localId: id, type: valueType, loc };
9501
9627
  for (const idx of idxs.slice(1)) {
9502
9628
  body.push({
9503
9629
  kind: "if",
9504
- cond: { kind: "strEq", negated: false, left: gRef, right: { kind: "strLit", value: "", type: STRING, loc }, type: BOOL, loc },
9630
+ cond: { kind: "unionIsTag", unionId: valueType.kind === "union" ? valueType.unionId : "", tag: valueType.kind === "union" ? lowerer.armTag(valueType.unionId, UNDEFINED_T) : -1, negated: false, value: gRef, type: BOOL, loc },
9505
9631
  then: [{ kind: "assign", localId: id, value: elem(idx), loc }],
9506
9632
  else_: null,
9507
9633
  loc,
@@ -9595,6 +9721,15 @@ export function lowerFieldRead(lowerer, expr) {
9595
9721
  if (receiverIr?.kind === "record") {
9596
9722
  const shape = lowerer.shapes.get(receiverIr.shapeId);
9597
9723
  if (shape?.indexValue && !shape.fields.some((f) => f.name === expr.name.text)) {
9724
+ const actual = tryLowerExpression(lowerer, expr.expression);
9725
+ if (actual?.type.kind === "dyn")
9726
+ return { kind: "dynKeyGet", value: actual,
9727
+ key: { kind: "strLit", value: expr.name.text, type: STRING, loc: locOf(expr.name) }, type: DYN, loc: locOf(expr) };
9728
+ if (actual?.type.kind === "record") {
9729
+ const field = lowerer.shapes.get(actual.type.shapeId)?.fields.find((field) => field.name === expr.name.text);
9730
+ if (field)
9731
+ return { kind: "recordGet", obj: actual, shapeId: actual.type.shapeId, field: field.name, type: field.type, loc: locOf(expr) };
9732
+ }
9598
9733
  lowerer.unsupported("SC1090", expr, `dot access to index-signature keys (spell it r["${expr.name.text}"] — brackets are the index-signature form)`);
9599
9734
  }
9600
9735
  }
@@ -9875,6 +10010,10 @@ function lowerUnionKeyedRead(lowerer, expr, unionId, value, key, literalField) {
9875
10010
  * or accessor dispatch. Resolve the property from the represented class;
9876
10011
  * the optional checker view must not turn its getter into a record read. */
9877
10012
  function classFieldTarget(lowerer, receiverNode, receiverType, fieldName, saved) {
10013
+ const represented = saved ?? lowerer.lowerExpr(receiverNode);
10014
+ if (represented.type.kind === "dyn" && isJsSourceFile(receiverNode.getSourceFile()) && !fieldName.startsWith("#")) {
10015
+ return { container: "dynamic", obj: represented, field: fieldName, fieldType: DYN };
10016
+ }
9878
10017
  const info = lowerer.classes.get(receiverType.className);
9879
10018
  if (!info) {
9880
10019
  // A receiver typed as a class whose collection deferred: the
@@ -9884,14 +10023,14 @@ function classFieldTarget(lowerer, receiverNode, receiverType, fieldName, saved)
9884
10023
  }
9885
10024
  const fieldType = info.fields.get(fieldName);
9886
10025
  const lowerObjectReceiver = () => {
9887
- let obj = saved ?? lowerer.lowerExpr(receiverNode);
10026
+ let obj = represented;
9888
10027
  if (obj.type.kind === "union") {
9889
10028
  const helper = lowerer.narrowedArmHelper(obj.type.unionId, receiverType, locOf(receiverNode));
9890
10029
  obj = helper
9891
10030
  ? { kind: "call", callee: helper, args: [obj], type: receiverType, loc: locOf(receiverNode) }
9892
10031
  : lowerer.maybeNarrow(obj, receiverNode);
9893
10032
  }
9894
- return obj.type.kind === "dyn" ? lowerer.coerceInto(receiverNode, obj, receiverType) : obj;
10033
+ return lowerer.coerceInto(receiverNode, obj, receiverType);
9895
10034
  };
9896
10035
  if (fieldName === "cause" && receiverType.className !== "%DOMException") {
9897
10036
  let root = info;
@@ -9903,6 +10042,11 @@ function classFieldTarget(lowerer, receiverNode, receiverType, fieldName, saved)
9903
10042
  }
9904
10043
  if (fieldType) {
9905
10044
  const obj = lowerObjectReceiver();
10045
+ if (isJsSourceFile(receiverNode.getSourceFile()) && !fieldName.startsWith("#") &&
10046
+ [...lowerer.classes.values()].some((candidate) => lowerer.isSubclassOf(candidate.def.name, receiverType.className) &&
10047
+ (candidate.methods.has(`get:${fieldName}`) || candidate.methods.has(`set:${fieldName}`)))) {
10048
+ return { container: "dynamic", obj: lowerer.coerceToExpected(obj, DYN), field: fieldName, fieldType: DYN };
10049
+ }
9906
10050
  return { container: "class", obj, className: receiverType.className, field: fieldName, fieldType };
9907
10051
  }
9908
10052
  // Accessor property: either half declared anywhere on the chain
@@ -9920,6 +10064,12 @@ function classFieldTarget(lowerer, receiverNode, receiverType, fieldName, saved)
9920
10064
  fieldType: getF ? getF.sig.ret : setF.sig.params[0].type,
9921
10065
  };
9922
10066
  }
10067
+ if (info.decl && isJsSourceFile(info.decl.getSourceFile())) {
10068
+ const property = lowerer.checker.getPropertyOfType(lowerer.checker.getTypeAtLocation(receiverNode), fieldName);
10069
+ if (property && lowerer.checker.declarationsOf(property).some((declaration) => ts.isPropertyAccessExpression(declaration) || ts.isBinaryExpression(declaration) || ts.isElementAccessExpression(declaration))) {
10070
+ return { container: "dynamic", obj: lowerer.coerceToExpected(lowerObjectReceiver(), DYN), field: fieldName, fieldType: DYN };
10071
+ }
10072
+ }
9923
10073
  return null;
9924
10074
  }
9925
10075
  /** A structural assertion can leave the value in its original class
@@ -9945,6 +10095,8 @@ function representedClassFieldTarget(lowerer, receiverNode, fieldName, value) {
9945
10095
  * receivers) a declared accessor property. Returns the pieces of a
9946
10096
  * fieldSet/recordSet/accessor-call (minus value/kind) or null. */
9947
10097
  export function fieldTarget(lowerer, access) {
10098
+ if (lowerer.cjsLocalModuleBindingOf(access.expression))
10099
+ return null;
9948
10100
  if (lowerer.chainBlocked(access))
9949
10101
  return null;
9950
10102
  if (access.name.text === "stackTraceLimit" && lowerer.isStdlibGlobal(access.expression, "Error")) {
@@ -10059,8 +10211,17 @@ export function fieldTarget(lowerer, access) {
10059
10211
  return declaredArms.every((a) => ivArms.some((b) => typeEquals(a, b)));
10060
10212
  };
10061
10213
  if (!nameSym || nameSym.name === ts.InternalSymbolName.Index || canonicalized()) {
10062
- const obj = lowerer.lowerExpr(access.expression);
10063
- return { container: "recordOvf", obj, shapeId: receiverIr.shapeId, field: access.name.text, fieldType: shape.indexValue };
10214
+ let obj = lowerer.lowerExpr(access.expression);
10215
+ if (obj.type.kind === "union" && lowerer.armTag(obj.type.unionId, UNDEFINED_T) >= 0) {
10216
+ const present = lowerer.stripUndefinedArm(obj.type);
10217
+ obj = present.kind === "record" ? lowerer.runtimeOptionalPropertyReceiver(access.expression, obj, present, access.name.text) ?? obj : lowerer.maybeNarrow(obj, access.expression);
10218
+ }
10219
+ if (obj.type.kind !== "record")
10220
+ return null;
10221
+ const actualShape = lowerer.shapes.get(obj.type.shapeId);
10222
+ if (!actualShape?.indexValue)
10223
+ return null;
10224
+ return { container: "recordOvf", obj, shapeId: obj.type.shapeId, field: access.name.text, fieldType: actualShape.indexValue };
10064
10225
  }
10065
10226
  }
10066
10227
  return null;
@@ -10158,6 +10319,11 @@ function symbolFieldTarget(lowerer, expr) {
10158
10319
  * tsc-clean (the property types as the setter's param), but Node yields
10159
10320
  * undefined, which these property types cannot represent. */
10160
10321
  export function fieldGetExpr(lowerer, target, loc, blame) {
10322
+ if (target.container === "dynamic")
10323
+ return {
10324
+ kind: "dynKeyGet", value: target.obj,
10325
+ key: { kind: "strLit", value: target.field, type: STRING, loc }, type: DYN, loc,
10326
+ };
10161
10327
  if (target.container === "class" && (target.field === "message" || target.field === "name") && (target.className === "%Error" || lowerer.isSubclassOf(target.className, "%Error")))
10162
10328
  return errorPropertyRead(lowerer, target.obj, target.field);
10163
10329
  if (target.container === "errorStackLimit") {
@@ -10267,6 +10433,11 @@ export function fieldGetExpr(lowerer, target, loc, blame) {
10267
10433
  * call). A write to a getter-only property never gets here in a clean
10268
10434
  * program (tsc's TS2540 is the fence); the rejection is the backstop. */
10269
10435
  export function fieldSetStmt(lowerer, target, value, loc, blame) {
10436
+ if (target.container === "dynamic")
10437
+ return {
10438
+ kind: "exprStmt", expr: { kind: "libCall", fn: "dyn.keySet",
10439
+ args: [target.obj, { kind: "strLit", value: target.field, type: STRING, loc }, lowerer.coerceToExpected(value, DYN)], type: VOID, loc }, loc,
10440
+ };
10270
10441
  if (target.container === "class" && (target.field === "message" || target.field === "name") && (target.className === "%Error" || lowerer.isSubclassOf(target.className, "%Error")))
10271
10442
  return errorPropertyWrite(lowerer, target.obj, value, target.field);
10272
10443
  if (target.container === "errorStackLimit") {
@@ -10434,7 +10605,7 @@ export function lowerPromiseAllTupleCall(lowerer, call, access) {
10434
10605
  const loc = locOf(call);
10435
10606
  const inner = first.inner;
10436
10607
  const entryT = { kind: "promise", inner };
10437
- const elems = argNode.elements.map((el) => lowerer.lowerExpr(el));
10608
+ const elems = argNode.elements.map((el) => lowerer.lowerExprExpecting(el, entryT));
10438
10609
  const entries = { kind: "arrayLit", elems, type: arrayOf(entryT), loc };
10439
10610
  const type = inner.kind === "void"
10440
10611
  ? { kind: "promise", inner: VOID }
@@ -10466,7 +10637,10 @@ function lowerFieldCompoundValue(lowerer, access, op, rhsNode, loc) {
10466
10637
  // NaN — SEMANTICS.md), combine, write back (dyn.keySet). The
10467
10638
  // receiver and member read are saved before evaluating the RHS.
10468
10639
  if (ts.isPropertyAccessExpression(access)) {
10469
- const probed = tryLowerExpression(lowerer, access.expression);
10640
+ let probed = tryLowerExpression(lowerer, access.expression);
10641
+ const staticClass = probed?.type.kind === "classval" ? lowerer.classes.get(probed.type.className) : undefined;
10642
+ if (probed && staticClass && hasRuntimeStatics(staticClass))
10643
+ probed = lowerer.coerceToExpected(probed, DYN);
10470
10644
  if (probed?.type.kind === "dyn") {
10471
10645
  const receiver = save(probed, "%compoundReceiver");
10472
10646
  const key = { kind: "strLit", value: access.name.text, type: STRING, loc: locOf(access.name) };
@@ -10475,6 +10649,14 @@ function lowerFieldCompoundValue(lowerer, access, op, rhsNode, loc) {
10475
10649
  const rhs = save(rhsNode
10476
10650
  ? lowerer.lowerExpr(rhsNode)
10477
10651
  : { kind: "numLit", value: 1, type: F64, loc }, "%compoundRhs");
10652
+ if (isJsSourceFile(access.getSourceFile()) && lowerer.dynConvertible(rhs.type)) {
10653
+ const numeric = ["-", "*", "/", "%", "**"].includes(op);
10654
+ const right = lowerer.coerceToExpected(rhs, DYN);
10655
+ const value = save({ kind: "libCall", fn: op === "+" ? "dyn.add" : numeric ? "dyn.arithmetic" : "dyn.bitwise",
10656
+ args: op === "+" ? [read, right] : [read, right, { kind: "strLit", value: op, type: STRING, loc }], type: DYN, loc }, "%compoundResult");
10657
+ body.push({ kind: "exprStmt", expr: { kind: "libCall", fn: "dyn.keySet", args: [receiver, key, value], type: VOID, loc }, loc });
10658
+ return { kind: "seqExpr", stmts: body, result: value, type: DYN, loc };
10659
+ }
10478
10660
  const numericRhs = rhs.type.kind === "dyn"
10479
10661
  ? { kind: "dynCheck", value: rhs, type: F64, loc: rhs.loc }
10480
10662
  : lowerOptionalNumber(lowerer, rhs, loc);
@@ -10512,35 +10694,12 @@ function lowerFieldCompoundValue(lowerer, access, op, rhsNode, loc) {
10512
10694
  value = { kind: "bin", op, left: read, right: numericRhs, type: F64, loc };
10513
10695
  }
10514
10696
  else if (target.fieldType.kind === "dyn" &&
10515
- isJsSourceFile(access.getSourceFile()) &&
10516
- (op === "+" || op === "-" || op === "*" || op === "/" || op === "%" || op === "**")) {
10517
- // CHECKED-DYNAMIC fields (implicit-any ctor assignments —
10518
- // countdown.js's `this[kLimit]` shape with a plain name) follow the
10519
- // JS dyn-operand binary stance: arithmetic CHECKS the dyn side to
10520
- // number (dynCheck — the catchable TypeError, never a silent
10521
- // ToNumber; SEMANTICS.md) and computes natively; the result boxes
10522
- // back into the field's dyn slot. `+=` with a string RHS is the
10523
- // string-context read: check to string, concat, box back.
10524
- const checkNum = (e) => e.type.kind === "dyn" ? { kind: "dynCheck", value: e, type: F64, loc: e.loc } : e;
10525
- if (op === "+" && rhs.type.kind === "string") {
10526
- const concat = {
10527
- kind: "strConcat",
10528
- // String-context read: JS's String(unknown) over the field —
10529
- // the JS-exact dyn walker, never a checked cast.
10530
- left: { kind: "toString", operand: read, type: STRING, loc },
10531
- right: rhs,
10532
- type: STRING,
10533
- loc,
10534
- };
10535
- value = { kind: "dynFrom", value: concat, type: DYN, loc };
10536
- }
10537
- else if (rhs.type.kind === "f64" || rhs.type.kind === "dyn") {
10538
- const bin = { kind: "bin", op, left: checkNum(read), right: checkNum(rhs), type: F64, loc };
10539
- value = { kind: "dynFrom", value: bin, type: DYN, loc };
10540
- }
10541
- else {
10542
- lowerer.unsupported("SC1043", access);
10543
- }
10697
+ isJsSourceFile(access.getSourceFile())) {
10698
+ const numeric = ["-", "*", "/", "%", "**"].includes(op);
10699
+ const left = lowerer.coerceToExpected(read, DYN);
10700
+ const right = lowerer.coerceToExpected(rhs, DYN);
10701
+ value = { kind: "libCall", fn: op === "+" ? "dyn.add" : numeric ? "dyn.arithmetic" : "dyn.bitwise",
10702
+ args: op === "+" ? [left, right] : [left, right, { kind: "strLit", value: op, type: STRING, loc }], type: DYN, loc };
10544
10703
  }
10545
10704
  else {
10546
10705
  lowerer.unsupported("SC1043", access);