@scriptc/compiler 0.2.0 → 0.2.2

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 (284) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +84 -19
  2. package/dist/backend/cycle-analysis.js +1 -0
  3. package/dist/backend/cycle-analysis.js.map +1 -1
  4. package/dist/backend/llvm/classes.js +21 -5
  5. package/dist/backend/llvm/classes.js.map +1 -1
  6. package/dist/backend/llvm/dyn.d.ts +8 -0
  7. package/dist/backend/llvm/dyn.js +247 -108
  8. package/dist/backend/llvm/dyn.js.map +1 -1
  9. package/dist/backend/llvm/emitter.d.ts +6 -3
  10. package/dist/backend/llvm/emitter.js +99 -25
  11. package/dist/backend/llvm/emitter.js.map +1 -1
  12. package/dist/backend/llvm/emitter.test.js +9 -1
  13. package/dist/backend/llvm/emitter.test.js.map +1 -1
  14. package/dist/backend/llvm/expr-bytes.d.ts +1 -1
  15. package/dist/backend/llvm/expr-bytes.js +28 -17
  16. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  17. package/dist/backend/llvm/expr-containers.js +5 -0
  18. package/dist/backend/llvm/expr-containers.js.map +1 -1
  19. package/dist/backend/llvm/expr-control.js +1 -1
  20. package/dist/backend/llvm/expr-control.js.map +1 -1
  21. package/dist/backend/llvm/expr-dynamic.js +47 -13
  22. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  23. package/dist/backend/llvm/expr-primitives.js +11 -1
  24. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  25. package/dist/backend/llvm/expr-records.js +11 -3
  26. package/dist/backend/llvm/expr-records.js.map +1 -1
  27. package/dist/backend/llvm/expr-stream-bridges.js +187 -18
  28. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  29. package/dist/backend/llvm/expr-stream-callbacks.d.ts +2 -2
  30. package/dist/backend/llvm/expr-stream-callbacks.js +7 -57
  31. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
  32. package/dist/backend/llvm/lib-dispatch.js +41 -3
  33. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  34. package/dist/backend/llvm/lib-filesystem.js +12 -9
  35. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  36. package/dist/backend/llvm/lib-process.js +23 -3
  37. package/dist/backend/llvm/lib-process.js.map +1 -1
  38. package/dist/backend/llvm/lib-shared.js +80 -3
  39. package/dist/backend/llvm/lib-shared.js.map +1 -1
  40. package/dist/backend/llvm/shapes.js +8 -2
  41. package/dist/backend/llvm/shapes.js.map +1 -1
  42. package/dist/backend/may-throw.js +4 -0
  43. package/dist/backend/may-throw.js.map +1 -1
  44. package/dist/backend/native-codegen.d.ts +1 -1
  45. package/dist/backend/native-codegen.js +4 -3
  46. package/dist/backend/native-codegen.js.map +1 -1
  47. package/dist/backend/native-codegen.test.js +11 -0
  48. package/dist/backend/native-codegen.test.js.map +1 -1
  49. package/dist/backend/native-toolchain.d.ts +3 -6
  50. package/dist/backend/native-toolchain.js +53 -23
  51. package/dist/backend/native-toolchain.js.map +1 -1
  52. package/dist/backend/native-toolchain.test.js +72 -0
  53. package/dist/backend/native-toolchain.test.js.map +1 -1
  54. package/dist/backend/runtime-abi.d.ts +2 -2
  55. package/dist/backend/runtime-abi.js +2 -2
  56. package/dist/backend/runtime-pack-native.js +4 -1
  57. package/dist/backend/runtime-pack-native.js.map +1 -1
  58. package/dist/backend/runtime-pack-targets.test.js +1 -1
  59. package/dist/backend/runtime-pack.test.js +1 -1
  60. package/dist/backend/target-diagnostics.d.ts +5 -0
  61. package/dist/backend/target-diagnostics.js +72 -1
  62. package/dist/backend/target-diagnostics.js.map +1 -1
  63. package/dist/backend/target-diagnostics.test.d.ts +1 -0
  64. package/dist/backend/target-diagnostics.test.js +68 -0
  65. package/dist/backend/target-diagnostics.test.js.map +1 -0
  66. package/dist/backend/targets.js +10 -6
  67. package/dist/backend/targets.js.map +1 -1
  68. package/dist/backend/targets.test.js +7 -0
  69. package/dist/backend/targets.test.js.map +1 -1
  70. package/dist/compat/fetch-profile.js +34 -4
  71. package/dist/compat/fetch-profile.js.map +1 -1
  72. package/dist/coverage/surface-manifest.js +5 -3
  73. package/dist/coverage/surface-manifest.js.map +1 -1
  74. package/dist/diagnostics/diagnostic.js +2 -7
  75. package/dist/diagnostics/diagnostic.js.map +1 -1
  76. package/dist/executable/executable-cache.d.ts +7 -3
  77. package/dist/executable/executable-cache.js +47 -11
  78. package/dist/executable/executable-cache.js.map +1 -1
  79. package/dist/executable/executable-cache.test.js +109 -2
  80. package/dist/executable/executable-cache.test.js.map +1 -1
  81. package/dist/executable/prepare.js +2 -1
  82. package/dist/executable/prepare.js.map +1 -1
  83. package/dist/frontend/builtin-modules.d.ts +1 -1
  84. package/dist/frontend/builtin-modules.js +1 -1
  85. package/dist/frontend/builtin-modules.js.map +1 -1
  86. package/dist/frontend/function-completion.d.ts +6 -0
  87. package/dist/frontend/function-completion.js +50 -0
  88. package/dist/frontend/function-completion.js.map +1 -0
  89. package/dist/frontend/lowering/abstract-equality.js +5 -1
  90. package/dist/frontend/lowering/abstract-equality.js.map +1 -1
  91. package/dist/frontend/lowering/checked-iterable-spread.d.ts +4 -0
  92. package/dist/frontend/lowering/checked-iterable-spread.js +30 -0
  93. package/dist/frontend/lowering/checked-iterable-spread.js.map +1 -0
  94. package/dist/frontend/lowering/checked-promise-all.d.ts +5 -0
  95. package/dist/frontend/lowering/checked-promise-all.js +31 -0
  96. package/dist/frontend/lowering/checked-promise-all.js.map +1 -0
  97. package/dist/frontend/lowering/class-callbacks.d.ts +4 -4
  98. package/dist/frontend/lowering/class-callbacks.js +29 -17
  99. package/dist/frontend/lowering/class-callbacks.js.map +1 -1
  100. package/dist/frontend/lowering/class-construction.d.ts +14 -0
  101. package/dist/frontend/lowering/class-construction.js +185 -0
  102. package/dist/frontend/lowering/class-construction.js.map +1 -0
  103. package/dist/frontend/lowering/class-descriptors.d.ts +2 -1
  104. package/dist/frontend/lowering/class-descriptors.js +58 -10
  105. package/dist/frontend/lowering/class-descriptors.js.map +1 -1
  106. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +36 -1
  107. package/dist/frontend/lowering/class-dynamic-dispatch.js +965 -91
  108. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  109. package/dist/frontend/lowering/class-dynamic-dispatch.test.js +66 -3
  110. package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
  111. package/dist/frontend/lowering/class-instance-constructor.d.ts +1 -1
  112. package/dist/frontend/lowering/class-instance-constructor.js +15 -42
  113. package/dist/frontend/lowering/class-instance-constructor.js.map +1 -1
  114. package/dist/frontend/lowering/class-method-values.d.ts +20 -1
  115. package/dist/frontend/lowering/class-method-values.js +120 -24
  116. package/dist/frontend/lowering/class-method-values.js.map +1 -1
  117. package/dist/frontend/lowering/class-prototypes.d.ts +10 -3
  118. package/dist/frontend/lowering/class-prototypes.js +188 -21
  119. package/dist/frontend/lowering/class-prototypes.js.map +1 -1
  120. package/dist/frontend/lowering/class-runtime-statics.d.ts +8 -0
  121. package/dist/frontend/lowering/class-runtime-statics.js +84 -0
  122. package/dist/frontend/lowering/class-runtime-statics.js.map +1 -0
  123. package/dist/frontend/lowering/class-static-data.d.ts +1 -0
  124. package/dist/frontend/lowering/class-static-data.js +6 -4
  125. package/dist/frontend/lowering/class-static-data.js.map +1 -1
  126. package/dist/frontend/lowering/containers/bytes.js +66 -17
  127. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  128. package/dist/frontend/lowering/containers/string-and-regexp.js +24 -47
  129. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  130. package/dist/frontend/lowering/deferred-module-initializers.d.ts +13 -0
  131. package/dist/frontend/lowering/deferred-module-initializers.js +410 -0
  132. package/dist/frontend/lowering/deferred-module-initializers.js.map +1 -0
  133. package/dist/frontend/lowering/deferred-module-initializers.test.d.ts +1 -0
  134. package/dist/frontend/lowering/deferred-module-initializers.test.js +92 -0
  135. package/dist/frontend/lowering/deferred-module-initializers.test.js.map +1 -0
  136. package/dist/frontend/lowering/error-methods.d.ts +4 -1
  137. package/dist/frontend/lowering/error-methods.js +100 -1
  138. package/dist/frontend/lowering/error-methods.js.map +1 -1
  139. package/dist/frontend/lowering/expressions/native-proxy.js +3 -1
  140. package/dist/frontend/lowering/expressions/native-proxy.js.map +1 -1
  141. package/dist/frontend/lowering/expressions/nullish-assignment.js +19 -11
  142. package/dist/frontend/lowering/expressions/nullish-assignment.js.map +1 -1
  143. package/dist/frontend/lowering/expressions/object-literals.js +68 -7
  144. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  145. package/dist/frontend/lowering/expressions/optional-chains.d.ts +3 -4
  146. package/dist/frontend/lowering/expressions/optional-chains.js +72 -20
  147. package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
  148. package/dist/frontend/lowering/function-context.d.ts +11 -3
  149. package/dist/frontend/lowering/function-context.js +11 -5
  150. package/dist/frontend/lowering/function-context.js.map +1 -1
  151. package/dist/frontend/lowering/generator-dynamic-dispatch.d.ts +1 -0
  152. package/dist/frontend/lowering/generator-dynamic-dispatch.js +39 -1
  153. package/dist/frontend/lowering/generator-dynamic-dispatch.js.map +1 -1
  154. package/dist/frontend/lowering/lib-boundary.d.ts +2 -0
  155. package/dist/frontend/lowering/lib-boundary.js +54 -1
  156. package/dist/frontend/lowering/lib-boundary.js.map +1 -1
  157. package/dist/frontend/lowering/lower-builtin-values.d.ts +7 -1
  158. package/dist/frontend/lowering/lower-builtin-values.js +113 -3
  159. package/dist/frontend/lowering/lower-builtin-values.js.map +1 -1
  160. package/dist/frontend/lowering/lower-builtins.d.ts +10 -14
  161. package/dist/frontend/lowering/lower-builtins.js +443 -88
  162. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  163. package/dist/frontend/lowering/lower-calls.d.ts +8 -5
  164. package/dist/frontend/lowering/lower-calls.js +717 -142
  165. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  166. package/dist/frontend/lowering/lower-classes.d.ts +18 -13
  167. package/dist/frontend/lowering/lower-classes.js +1076 -188
  168. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  169. package/dist/frontend/lowering/lower-containers.d.ts +9 -0
  170. package/dist/frontend/lowering/lower-containers.js +172 -51
  171. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  172. package/dist/frontend/lowering/lower-dgram.js +3 -2
  173. package/dist/frontend/lowering/lower-dgram.js.map +1 -1
  174. package/dist/frontend/lowering/lower-exprs.d.ts +12 -8
  175. package/dist/frontend/lowering/lower-exprs.js +802 -232
  176. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  177. package/dist/frontend/lowering/lower-generators.js +17 -2
  178. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  179. package/dist/frontend/lowering/lower-inspect.js +15 -1
  180. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  181. package/dist/frontend/lowering/lower-island.d.ts +2 -0
  182. package/dist/frontend/lowering/lower-island.js +36 -10
  183. package/dist/frontend/lowering/lower-island.js.map +1 -1
  184. package/dist/frontend/lowering/lower-island.test.d.ts +1 -0
  185. package/dist/frontend/lowering/lower-island.test.js +51 -0
  186. package/dist/frontend/lowering/lower-island.test.js.map +1 -0
  187. package/dist/frontend/lowering/lower-modules.d.ts +1 -3
  188. package/dist/frontend/lowering/lower-modules.js +380 -73
  189. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  190. package/dist/frontend/lowering/lower-modules.test.d.ts +1 -0
  191. package/dist/frontend/lowering/lower-modules.test.js +107 -0
  192. package/dist/frontend/lowering/lower-modules.test.js.map +1 -0
  193. package/dist/frontend/lowering/lower-stmts.d.ts +7 -3
  194. package/dist/frontend/lowering/lower-stmts.js +221 -47
  195. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  196. package/dist/frontend/lowering/lower-stmts.test.d.ts +1 -0
  197. package/dist/frontend/lowering/lower-stmts.test.js +77 -0
  198. package/dist/frontend/lowering/lower-stmts.test.js.map +1 -0
  199. package/dist/frontend/lowering/lower-stream.js +3 -1
  200. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  201. package/dist/frontend/lowering/lower-url.d.ts +2 -1
  202. package/dist/frontend/lowering/lower-url.js +32 -9
  203. package/dist/frontend/lowering/lower-url.js.map +1 -1
  204. package/dist/frontend/lowering/lowerer.d.ts +53 -10
  205. package/dist/frontend/lowering/lowerer.js +390 -77
  206. package/dist/frontend/lowering/lowerer.js.map +1 -1
  207. package/dist/frontend/lowering/lowerer.test.js +187 -3
  208. package/dist/frontend/lowering/lowerer.test.js.map +1 -1
  209. package/dist/frontend/lowering/module-namespace-elements.d.ts +7 -0
  210. package/dist/frontend/lowering/module-namespace-elements.js +54 -0
  211. package/dist/frontend/lowering/module-namespace-elements.js.map +1 -0
  212. package/dist/frontend/lowering/object-factory-new.d.ts +4 -3
  213. package/dist/frontend/lowering/object-factory-new.js +27 -14
  214. package/dist/frontend/lowering/object-factory-new.js.map +1 -1
  215. package/dist/frontend/lowering/surfaces.d.ts +3 -0
  216. package/dist/frontend/lowering/surfaces.js +48 -19
  217. package/dist/frontend/lowering/surfaces.js.map +1 -1
  218. package/dist/frontend/lowering/text-decoder-encoding.d.ts +2 -0
  219. package/dist/frontend/lowering/text-decoder-encoding.js +8 -0
  220. package/dist/frontend/lowering/text-decoder-encoding.js.map +1 -1
  221. package/dist/frontend/lowering/text-decoder-encoding.test.js +2 -1
  222. package/dist/frontend/lowering/text-decoder-encoding.test.js.map +1 -1
  223. package/dist/frontend/lowering/unregistered-class-types.test.js +3 -3
  224. package/dist/frontend/lowering/unregistered-class-types.test.js.map +1 -1
  225. package/dist/frontend/npm-static-prune.js +116 -34
  226. package/dist/frontend/npm-static-prune.js.map +1 -1
  227. package/dist/frontend/npm-static-prune.test.js +8 -0
  228. package/dist/frontend/npm-static-prune.test.js.map +1 -1
  229. package/dist/frontend/program.d.ts +1 -1
  230. package/dist/frontend/program.js +57 -26
  231. package/dist/frontend/program.js.map +1 -1
  232. package/dist/frontend/program.test.js +18 -0
  233. package/dist/frontend/program.test.js.map +1 -1
  234. package/dist/frontend/ts7/ast.js +4 -3
  235. package/dist/frontend/ts7/ast.js.map +1 -1
  236. package/dist/frontend/ts7/semantic-json.js +5 -10
  237. package/dist/frontend/ts7/semantic-json.js.map +1 -1
  238. package/dist/frontend/type-mapper.d.ts +9 -1
  239. package/dist/frontend/type-mapper.js +169 -23
  240. package/dist/frontend/type-mapper.js.map +1 -1
  241. package/dist/frontend/type-mapper.test.js +23 -0
  242. package/dist/frontend/type-mapper.test.js.map +1 -1
  243. package/dist/frontend/union-discriminants.d.ts +1 -1
  244. package/dist/frontend/union-discriminants.js +24 -9
  245. package/dist/frontend/union-discriminants.js.map +1 -1
  246. package/dist/index.js +16 -10
  247. package/dist/index.js.map +1 -1
  248. package/dist/ir/analysis.js +2 -0
  249. package/dist/ir/analysis.js.map +1 -1
  250. package/dist/ir/ir.d.ts +74 -41
  251. package/dist/ir/ir.js +167 -43
  252. package/dist/ir/ir.js.map +1 -1
  253. package/dist/ir/ir.test.js +35 -0
  254. package/dist/ir/ir.test.js.map +1 -1
  255. package/dist/ir/serialize.js +35 -3
  256. package/dist/ir/serialize.js.map +1 -1
  257. package/dist/ir/serialize.test.js +26 -1
  258. package/dist/ir/serialize.test.js.map +1 -1
  259. package/dist/ir/traverse.d.ts +0 -3
  260. package/dist/ir/traverse.js +33 -20
  261. package/dist/ir/traverse.js.map +1 -1
  262. package/dist/ir/validate.js +136 -16
  263. package/dist/ir/validate.js.map +1 -1
  264. package/dist/ir/validate.test.js +77 -1
  265. package/dist/ir/validate.test.js.map +1 -1
  266. package/dist/library/compiler-self-identity.js +1 -1
  267. package/dist/library/compiler-self-identity.test.js +2 -2
  268. package/dist/library/compiler-self-identity.test.js.map +1 -1
  269. package/dist/library/int-infer.d.ts +2 -2
  270. package/dist/library/int-infer.js +10 -7
  271. package/dist/library/int-infer.js.map +1 -1
  272. package/dist/library/int-infer.test.js +44 -0
  273. package/dist/library/int-infer.test.js.map +1 -1
  274. package/dist/library/prepare.js +2 -1
  275. package/dist/library/prepare.js.map +1 -1
  276. package/dist/native/sanitizer.js +3 -1
  277. package/dist/native/sanitizer.js.map +1 -1
  278. package/dist/native/toolchain.d.ts +1 -1
  279. package/dist/native/toolchain.js +26 -6
  280. package/dist/native/toolchain.js.map +1 -1
  281. package/dist/native/toolchain.test.js +53 -1
  282. package/dist/native/toolchain.test.js.map +1 -1
  283. package/package.json +20 -20
  284. package/surface-manifest.json +170 -93
@@ -10,24 +10,25 @@ import { bodyReadsArguments } from "../arguments-usage.js";
10
10
  import { lowerGenMethodCall } from "./lower-generators.js";
11
11
  import { lowerClassSymbolMethodCall } from "./symbol-methods.js";
12
12
  import { errorToStringCall } from "./error-methods.js";
13
- import { lowerClassPrototypeAssign } from "./class-prototypes.js";
13
+ import { lowerClassPrototypeAssign, lowerClassPrototypeDescriptors } from "./class-prototypes.js";
14
14
  import { BYTES_ELEMENT_NAME, BIGINT_T, BOOL, CAUGHT, DYN, F64, JSVAL, NULL_T, STRING, SYMBOL_T, UNDEFINED_T, VOID, arrayOf, canBoxFuncIntoDyn, canConvertToDyn, canDynCheckTo, canMarshalTypedFuncIntoIsland, ffiClassType, ffiSourceParamTypes, funcOf, isDynTypedRefType, isFfiCallbackParam, isFfiContextParam, isFfiReleaseParam, isUnitType, shapeHasAccessorSlots, typeEquals } from "../../ir/ir.js";
15
15
  import { isJsSourceFile, isNodeEsmFile, locOf, requireSpecOf } from "../program.js";
16
16
  import { genResultRecord, isGenericCallableMemberType, jsOpenObjectType, typeKey } from "../type-mapper.js";
17
- import { PoisonError, dynFallbackType, dynUndefinedExpr, importCallHandleType, jsFuncNameOf, newFnCtx, nodeThrowExpr, staticImportNamespaceType } from "./lowerer.js";
18
- import { enforceLibBoundary } from "./lib-boundary.js";
19
- import { NARROW_FIRST, STRING_INDEX_METHODS, STR_METHODS, builtinFenceHintOf, builtinModuleFnOf } from "./surfaces.js";
17
+ import { PoisonError, dynFallbackType, dynUndefinedExpr, importCallHandleType, jsFuncNameOf, neverTaintedJsType, newFnCtx, nodeThrowExpr, staticImportNamespaceType } from "./lowerer.js";
18
+ import { enforceLibBoundary, lowerSurplusCalls } from "./lib-boundary.js";
19
+ import { NARROW_FIRST, STRING_INDEX_METHODS, STR_METHODS, builtinFenceHintOf, builtinModuleFnOf, stdlibGlobalNameOf } from "./surfaces.js";
20
20
  import { ffiBindingDiag, ffiSignatureDiag, libCallbackDiag, requiresDynamicDiag } from "../../diagnostics/diagnostic.js";
21
21
  import { mixinFnShapeOf } from "./lower-mixins.js";
22
- import { dynStringReceiver, lowerArrayConstructor, lowerArrayFromCall, lowerArrayOfCall, lowerDynArrayFilterCall, lowerDynArrayFlatMapCall, lowerGroupByStaticCall, lowerIteratorHelperCall, lowerObjectAssignIndexShape, lowerObjectFromEntriesCall, lowerObjectIterOverIndexShape, lowerTupleReadMethodCall } from "./lower-containers.js";
22
+ import { dynStringReceiver, lowerArrayConstructor, lowerArrayFromCall, lowerArrayOfCall, lowerDynArrayFilterCall, lowerDynArrayFlatMapCall, lowerGroupByStaticCall, lowerIteratorHelperCall, lowerObjectAssignIndexShape, lowerObjectConstructor, lowerObjectFromEntriesCall, lowerObjectIterOverIndexShape, lowerTupleReadMethodCall } from "./lower-containers.js";
23
23
  import { lowerBytesStaticCall } from "./containers/bytes.js";
24
24
  import { lowerRegexMethodCall, lowerStringIndexCall, lowerStringMethodCall, lowerStringPaddingCall, lowerStringSplitCall } from "./containers/string-and-regexp.js";
25
- import { createRequireSpecOf, lowerChildStreamMethodCall, lowerChildWriterMethodCall, lowerCreateRequireCall, lowerCryptoHashMethodCall, lowerDirentMethodCall, lowerFileHandleMethodCall, lowerImportMetaResolveCall, lowerNodeModuleCall, lowerPerfHooksCall, lowerProcStreamMethodCall, lowerReflectApplyCall, lowerRequireResolveCall, lowerWatcherMethodCall } from "./lower-builtins.js";
26
- import { lowerAbsenceProbe, lowerPromiseAllTupleCall, lowerPromiseRejectCall, stringWrapperToString, templateRawTextOf } from "./lower-exprs.js";
25
+ import { createRequireSpecOf, lowerChildStreamMethodCall, lowerChildWriterMethodCall, lowerCreateRequireCall, lowerCryptoHashMethodCall, lowerDirentMethodCall, lowerFileHandleMethodCall, lowerImportMetaResolveCall, lowerNodeModuleCall, lowerPerfHooksCall, lowerProcStreamMethodCall, lowerReflectCall, lowerRequireResolveCall, lowerWatcherMethodCall } from "./lower-builtins.js";
26
+ import { lowerAbsenceProbe, lowerPromiseAllTupleCall, lowerPromiseRejectCall, stringWrapperToString, symbolFieldInfo, templateRawTextOf } from "./lower-exprs.js";
27
27
  import { isSafeToDiscard } from "./expressions/evaluation-safety.js";
28
28
  import { tryLowerExpression } from "./expressions/try-lower-expression.js";
29
+ import { hasRuntimeStatics } from "./class-runtime-statics.js";
29
30
  import { httpClientFnBindingOf, isStreamUndefCallExpr, lowerCompatReqStreamOptionalCall, lowerHttpClientFnCall } from "./lower-server.js";
30
- import { EMITTER_API_MEMBERS, exactInstanceClassOf, findGenericMethodOn, lowerClassGenericMethodCall, lowerStaticMethodCall, returnsOnlyThis } from "./lower-classes.js";
31
+ import { EMITTER_API_MEMBERS, exactClassOfReceiver, exactInstanceClassOf, findGenericMethodOn, lowerClassGenericMethodCall, lowerStaticMethodCall, lowerStaticFieldRead, returnsOnlyThis, storedClassValueType } from "./lower-classes.js";
31
32
  import { classCallbackCall, isClassCallback } from "./class-callbacks.js";
32
33
  import { emitterRooted, lowerEmitterMethodCall } from "./lower-event-emitter.js";
33
34
  import { lowerConsoleInspectArg, lowerFormatCall } from "./lower-inspect.js";
@@ -43,6 +44,10 @@ import { defaultAfterUndefined, lowerOptionalArgument, lowerStaticallyUndefinedA
43
44
  import { fenceSymbolFieldCopy } from "./symbol-fields.js";
44
45
  import { lowerClassDataDescriptor, lowerClassDescriptorRead } from "./class-descriptors.js";
45
46
  import { classStaticDataFor } from "./class-static-data.js";
47
+ import { jsBindingHasOpenWrites } from "./lower-stmts.js";
48
+ import { functionCanReturnUndefined } from "../function-completion.js";
49
+ import { checkedIterableSpread } from "./checked-iterable-spread.js";
50
+ import { lowerUrlFactory } from "./lower-url.js";
46
51
  export { bodyReadsArguments };
47
52
  /** The one func-type projection of completed parameter shapes. Typed rest
48
53
  * parameters keep their packed array as the trailing native ABI slot and
@@ -123,7 +128,38 @@ export const MAX_GENERIC_INSTANCES = 100;
123
128
  * - `...xs: T[]`: the ABI type is the array; call sites pack the surplus.
124
129
  */
125
130
  export function paramShape(lowerer, param) {
131
+ if (isJsSourceFile(param.getSourceFile()) && ts.isSetAccessorDeclaration(param.parent))
132
+ return { type: DYN, mode: "required" };
133
+ if (isJsSourceFile(param.getSourceFile()) && ts.isConstructorDeclaration(param.parent) && !param.dotDotDotToken) {
134
+ // Reflective JavaScript construction can supply values outside the
135
+ // constructor's documented usual types. Retain the actual arguments
136
+ // and apply checked conversions only at operations that need them.
137
+ return param.initializer ? { type: DYN, mode: "omittable", bodyType: DYN }
138
+ : { type: DYN, mode: param.questionToken ? "omittable" : "required" };
139
+ }
140
+ const executor = param.parent;
141
+ const construction = executor?.parent;
142
+ const nativeExecutor = executor && (ts.isArrowFunction(executor) || ts.isFunctionExpression(executor)) && ts.isNewExpression(construction) &&
143
+ construction.arguments?.[0] === executor && lowerer.isStdlibGlobal(construction.expression, "Promise");
144
+ if (!nativeExecutor && isJsSourceFile(param.getSourceFile()) && !param.type && !param.dotDotDotToken && !ts.isSetAccessorDeclaration(param.parent) &&
145
+ !/@(?:param|type)\b/.test(param.getSourceFile().text.slice(param.parent?.pos ?? param.pos, param.getStart()))) {
146
+ return param.initializer ? { type: DYN, mode: "omittable", bodyType: DYN } : { type: DYN, mode: "required" };
147
+ }
148
+ if (param.initializer && isJsSourceFile(param.getSourceFile()) && !param.type &&
149
+ !/@(?:param|type)\b/.test(param.getSourceFile().text.slice(param.parent?.pos ?? param.pos, param.getStart()))) {
150
+ return { type: DYN, mode: "omittable", bodyType: DYN };
151
+ }
152
+ // Inferred JS array patterns describe the bindings, not an exact tuple
153
+ // contract. Consume the actual iterable, including surplus elements.
154
+ if (ts.isArrayBindingPattern(param.name) && isJsSourceFile(param.getSourceFile()) && !param.type &&
155
+ !/@(?:param|type)\b/.test(param.getSourceFile().text.slice(param.parent?.pos ?? param.pos, param.getStart()))) {
156
+ if (param.dotDotDotToken)
157
+ return { type: DYN, mode: "dynRest" };
158
+ return param.initializer ? { type: DYN, mode: "omittable", bodyType: DYN } : { type: DYN, mode: "required" };
159
+ }
126
160
  if (lowerer.checkedCallbackParams.has(param)) {
161
+ if (param.dotDotDotToken)
162
+ return { type: DYN, mode: "dynRest" };
127
163
  return param.initializer
128
164
  ? { type: DYN, mode: "omittable", bodyType: DYN }
129
165
  : { type: DYN, mode: "required" };
@@ -203,11 +239,41 @@ export function paramShape(lowerer, param) {
203
239
  }
204
240
  if (param.initializer) {
205
241
  const raw = lowerer.irTypeOf(param.name);
242
+ // An optional JS array parameter is a live caller-owned buffer,
243
+ // including typed arrays passed through checked callbacks. Extracting
244
+ // a native array here would copy it and discard element writes.
245
+ if (isJsSourceFile(param.getSourceFile()) && !param.type &&
246
+ (raw.kind === "array" || raw.kind === "union" && lowerer.unions.get(raw.unionId)?.arms.some((arm) => arm.kind === "array"))) {
247
+ return { type: DYN, mode: "omittable", bodyType: DYN };
248
+ }
206
249
  return defaultParameterShape(lowerer, param, raw);
207
250
  }
208
- const type = lowerer.runtimeOptionalBindingType(param.name, lowerer.irTypeOf(param.name));
251
+ let type = lowerer.runtimeOptionalBindingType(param.name, lowerer.irTypeOf(param.name));
252
+ const body = param.parent?.body;
253
+ if (isJsSourceFile(param.getSourceFile()) && body &&
254
+ type.kind !== "dyn" && type.kind !== "jsval") {
255
+ const symbol = lowerer.checker.getSymbolAtLocation(param.name);
256
+ let acceptsUndefined = false;
257
+ ts.walkPreorder(body, (node) => {
258
+ if (acceptsUndefined || !ts.isBinaryExpression(node))
259
+ return;
260
+ const op = node.operatorToken.kind;
261
+ if (op !== ts.SyntaxKind.EqualsEqualsEqualsToken && op !== ts.SyntaxKind.ExclamationEqualsEqualsToken &&
262
+ op !== ts.SyntaxKind.EqualsEqualsToken && op !== ts.SyntaxKind.ExclamationEqualsToken)
263
+ return;
264
+ const checks = (value, absent) => ts.isIdentifier(value) && ts.isIdentifier(absent) && absent.text === "undefined" &&
265
+ (lowerer.typeOf(absent).flags & ts.TypeFlags.Undefined) !== 0 &&
266
+ lowerer.checker.getSymbolAtLocation(value) === symbol;
267
+ acceptsUndefined = checks(node.left, node.right) || checks(node.right, node.left);
268
+ });
269
+ // A JavaScript body that handles an absent argument defines a wider
270
+ // contract than its JSDoc's usual value. Checked callers must deliver
271
+ // undefined to that branch rather than reject it at the ABI boundary.
272
+ if (acceptsUndefined)
273
+ type = lowerer.promoteRuntimeOptionalParameter(param.name, type);
274
+ }
209
275
  if (type.kind === "void") {
210
- lowerer.unsupported("SC1090", param, "function parameters with void type");
276
+ return { type: DYN, mode: param.questionToken ? "omittable" : "required" };
211
277
  }
212
278
  if (param.questionToken && !lowerer.bareUndefinedArmedUnion(type) && type.kind !== "dyn" && type.kind !== "jsval") {
213
279
  // `x?: unknown` where unknown came from an annotation: undefined is
@@ -352,7 +418,7 @@ leading) {
352
418
  // before conversion to the dense checked-dynamic argument pack.
353
419
  value = { kind: "arrayLit", elems: [value], spreads: [0], type: value.type, loc: value.loc };
354
420
  }
355
- value = lowerer.coerceInto(arg.expression, value, DYN);
421
+ value = checkedIterableSpread(lowerer, value, arg.expression.getText(), loc);
356
422
  if (spreads === 1 && index === argNodes.length - 1) {
357
423
  stmts.push({ kind: "exprStmt", expr: {
358
424
  kind: "libCall", fn: "dyn.packPushSpread", args: [ref(), value, { kind: "strLit", value: arg.expression.getText(), type: STRING, loc }], type: VOID, loc,
@@ -624,8 +690,7 @@ leading) {
624
690
  lowerer.unsupported("SC1090", a, "spread arguments into fixed parameter positions (a spread can only fill a rest parameter)");
625
691
  }
626
692
  const v = lowerer.lowerExpr(a);
627
- if (v.kind !== "unitLit" && v.kind !== "numLit" && v.kind !== "strLit" &&
628
- v.kind !== "boolLit" && v.kind !== "varRef" && v.kind !== "closure") {
693
+ if (!isSafeToDiscard(v)) {
629
694
  lowerer.unsupported("SC1090", a, "surplus arguments with side effects (JS evaluates surplus arguments to a function without a rest parameter, then drops them; only effect-free surplus arguments compile)");
630
695
  }
631
696
  }
@@ -856,7 +921,7 @@ export function appendImplicitUndefinedReturn(lowerer, body, bodyReturn, loc) {
856
921
  /** A declaration's checker-derived IR return type. The unmappable-type
857
922
  * diagnostic points at `blame` (the name for top-level declarations, the
858
923
  * whole node for lambda-likes — preserving each caller's historical loc). */
859
- function hasExplicitJsDocReturn(decl) {
924
+ export function hasExplicitJsDocReturn(decl) {
860
925
  const sourceFile = decl.getSourceFile();
861
926
  return /@returns?\b/.test(sourceFile.text.slice(decl.pos, decl.getStart(sourceFile)));
862
927
  }
@@ -866,7 +931,19 @@ function promiseCarriesDyn(lowerer, type) {
866
931
  return type.kind === "union" &&
867
932
  (lowerer.unions.get(type.unionId)?.arms.some((arm) => promiseCarriesDyn(lowerer, arm)) ?? false);
868
933
  }
934
+ function producesConstructor(lowerer, type) {
935
+ let result = type;
936
+ for (let depth = 0; result && depth < 8; depth++) {
937
+ if (lowerer.checker.getConstructSignatures(result).length > 0)
938
+ return true;
939
+ const signatures = lowerer.checker.getCallSignatures(result);
940
+ result = signatures.length === 1 ? lowerer.checker.getReturnTypeOfSignature(signatures[0]) : undefined;
941
+ }
942
+ return false;
943
+ }
869
944
  export function declaredReturnType(lowerer, decl, blame) {
945
+ if (isJsSourceFile(decl.getSourceFile()) && ts.isGetAccessorDeclaration(decl))
946
+ return DYN;
870
947
  const sig = lowerer.checker.getSignatureFromDeclaration(decl);
871
948
  if (!sig)
872
949
  lowerer.unsupported("SC1090", decl, "this function form");
@@ -881,9 +958,36 @@ export function declaredReturnType(lowerer, decl, blame) {
881
958
  // (`.action(() => { throw ... })`). `never` VALUES stay unmapped.
882
959
  if (retTsType.flags & ts.TypeFlags.Never)
883
960
  return VOID;
884
- const mappedReturn = lowerer.mapTypeOf(retTsType);
961
+ let mappedReturn = lowerer.mapTypeOf(retTsType);
962
+ if (isJsSourceFile(decl.getSourceFile()) && decl.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword) &&
963
+ !decl.asteriskToken && mappedReturn?.kind !== "promise") {
964
+ const fallback = dynFallbackType(lowerer, decl, retTsType);
965
+ return fallback?.kind === "promise" ? fallback : { kind: "promise", inner: DYN };
966
+ }
967
+ if (mappedReturn && isJsSourceFile(decl.getSourceFile()) && functionCanReturnUndefined(decl))
968
+ mappedReturn = lowerer.withUndefinedArmOf(mappedReturn) ?? mappedReturn;
969
+ if (isJsSourceFile(decl.getSourceFile()) && mappedReturn?.kind === "void") {
970
+ let returnsValue = false;
971
+ const scan = (node) => {
972
+ if (node !== decl && ts.isFunctionLike(node))
973
+ return;
974
+ if (ts.isReturnStatement(node) && node.expression)
975
+ returnsValue = true;
976
+ node.forEachChild(scan);
977
+ };
978
+ scan(decl);
979
+ if (returnsValue)
980
+ return DYN;
981
+ }
982
+ if (isJsSourceFile(decl.getSourceFile()) && mappedReturn?.kind === "array")
983
+ return DYN;
984
+ if (isJsSourceFile(decl.getSourceFile()) && !decl.type && !hasExplicitJsDocReturn(decl) && mappedReturn?.kind === "record")
985
+ return DYN;
885
986
  if (isJsSourceFile(decl.getSourceFile()) && !decl.type && !hasExplicitJsDocReturn(decl) && mappedReturn?.kind === "date")
886
987
  return DYN;
988
+ if (isJsSourceFile(decl.getSourceFile()) && !decl.type && !hasExplicitJsDocReturn(decl) &&
989
+ mappedReturn?.kind === "union" && lowerer.unions.get(mappedReturn.unionId)?.arms.some((arm) => arm.kind === "func"))
990
+ return DYN;
887
991
  // JS inference assigns Number to arithmetic over any, although the
888
992
  // runtime operands can both be BigInts. Preserve that native result.
889
993
  if (isJsSourceFile(decl.getSourceFile()) && !decl.type && !hasExplicitJsDocReturn(decl) &&
@@ -944,10 +1048,13 @@ export function declaredReturnType(lowerer, decl, blame) {
944
1048
  // Native-only members (such as Int32Array layout offsets) cannot cross
945
1049
  // that boundary; their factories keep the native record ABI.
946
1050
  const asyncReturn = decl.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword) && mappedReturn?.kind === "promise";
947
- const recordReturn = asyncReturn ? mappedReturn.inner : mappedReturn;
1051
+ const recordReturn = asyncReturn && mappedReturn?.kind === "promise" ? mappedReturn.inner : mappedReturn;
1052
+ const recordArms = recordReturn?.kind === "union" ? lowerer.unions.get(recordReturn.unionId)?.arms : recordReturn ? [recordReturn] : undefined;
1053
+ const inferredRecordReturn = recordArms?.some((arm) => arm.kind === "record" || arm.kind === "object") &&
1054
+ recordArms.every((arm) => isUnitType(arm) || arm.kind === "record" || arm.kind === "object" && !hasExplicitJsDocReturn(decl));
948
1055
  if (isJsSourceFile(decl.getSourceFile()) &&
949
1056
  decl.type === undefined &&
950
- recordReturn?.kind === "record" &&
1057
+ recordReturn !== null && recordReturn !== undefined && inferredRecordReturn &&
951
1058
  lowerer.dynConvertible(recordReturn) &&
952
1059
  decl.parameters.every((p) => {
953
1060
  const mt = lowerer.mapTypeOf(lowerer.typeOf(p));
@@ -955,7 +1062,7 @@ export function declaredReturnType(lowerer, decl, blame) {
955
1062
  })) {
956
1063
  return asyncReturn ? { kind: "promise", inner: DYN } : DYN;
957
1064
  }
958
- const returnType = lowerer.mapTypeOf(retTsType);
1065
+ const returnType = mappedReturn;
959
1066
  if (!returnType) {
960
1067
  // JS inference residue (an `any` return, an unmappable union): the
961
1068
  // checked-dynamic fallback, exactly the declaration story in
@@ -1565,6 +1672,7 @@ export function lowerGenericInstance(lowerer, info, inst) {
1565
1672
  body.push(...lowerer.lowerStmts(bodyBlock.statements));
1566
1673
  if (fnCtx.inferReturn) {
1567
1674
  bodyReturn = resolveInferredReturn(lowerer, inst, fnCtx.inferReturn, body, decl);
1675
+ inst.returnType = bodyReturn;
1568
1676
  }
1569
1677
  appendImplicitUndefinedReturn(lowerer, body, bodyReturn, locOf(decl));
1570
1678
  }
@@ -1578,6 +1686,7 @@ export function lowerGenericInstance(lowerer, info, inst) {
1578
1686
  if (value.type.kind === "void") {
1579
1687
  body.push({ kind: "exprStmt", expr: value, loc: locOf(decl.body) });
1580
1688
  bodyReturn = resolveInferredReturn(lowerer, inst, fnCtx.inferReturn, body, decl);
1689
+ inst.returnType = bodyReturn;
1581
1690
  appendImplicitUndefinedReturn(lowerer, body, bodyReturn, locOf(decl));
1582
1691
  }
1583
1692
  else {
@@ -1585,6 +1694,7 @@ export function lowerGenericInstance(lowerer, info, inst) {
1585
1694
  fnCtx.inferReturn.entries.push({ stmt, node: decl.body });
1586
1695
  body.push(stmt);
1587
1696
  bodyReturn = resolveInferredReturn(lowerer, inst, fnCtx.inferReturn, body, decl);
1697
+ inst.returnType = bodyReturn;
1588
1698
  }
1589
1699
  }
1590
1700
  else {
@@ -1639,7 +1749,9 @@ export function lowerGenericInstance(lowerer, info, inst) {
1639
1749
  * adds JS's undefined; DYN when returns disagree (the checked-dynamic
1640
1750
  * result slot — today's shape). Same-key recursion PINNED the fallback
1641
1751
  * type mid-lowering (callers already hold it), so a pinned instance
1642
- * keeps it and the wrap pass coerces every return to the pin. */
1752
+ * keeps it and the wrap pass coerces every return to the pin. Callers
1753
+ * store the settled type on their full instance; this narrower view
1754
+ * can be a structural copy in native builds. */
1643
1755
  function resolveInferredReturn(lowerer, inst, infer, body, decl) {
1644
1756
  // The conservative completion test appendImplicitUndefinedReturn uses:
1645
1757
  // a body whose last statement isn't a terminator may complete without
@@ -1670,14 +1782,13 @@ function resolveInferredReturn(lowerer, inst, infer, body, decl) {
1670
1782
  else {
1671
1783
  final = DYN; // disagreeing returns: the checked-dynamic join
1672
1784
  }
1673
- inst.returnType = final;
1674
1785
  }
1675
1786
  // The wrap pass: settle every recorded return onto `final`, in place.
1787
+ // Write through the stored union arm: optional-field widening on a
1788
+ // local alias can otherwise introduce a record copy in native builds.
1676
1789
  for (const e of infer.entries) {
1677
1790
  if (e.stmt.kind !== "return")
1678
1791
  continue;
1679
- // Write through the recorded statement. A narrowed local can acquire a
1680
- // different record layout and copy it in the native compiler.
1681
1792
  const diagsBefore = lowerer.diags.length;
1682
1793
  try {
1683
1794
  if (e.stmt.value === null || e.stmt.value === undefined) {
@@ -2063,6 +2174,12 @@ function implicitDeclaredReturn(lowerer, info) {
2063
2174
  if (retTs.flags & (ts.TypeFlags.Null | ts.TypeFlags.Undefined))
2064
2175
  return DYN;
2065
2176
  if (lowerer.checker.isArrayType(retTs)) {
2177
+ // Inferred JavaScript arrays can hold values selected through a
2178
+ // mutable constructor registry. The checker may retain only one
2179
+ // constructor's element type; settle the result from the lowered
2180
+ // container instead of checking every element against that guess.
2181
+ if (!hasExplicitJsDocReturn(info.decl))
2182
+ return null;
2066
2183
  if (info.decl.parameters.some((param, index) => info.implicitParams?.[index] &&
2067
2184
  lowerer.mapTypeOf(lowerer.typeOf(param.name))?.kind === "array"))
2068
2185
  return null;
@@ -2076,6 +2193,39 @@ function implicitDeclaredReturn(lowerer, info) {
2076
2193
  return null;
2077
2194
  }
2078
2195
  const mapped = lowerer.mapTypeOf(retTs);
2196
+ // Mixed inferred results can select a closure or a class instance.
2197
+ // Their callable ABI is settled by the lowered body, including native
2198
+ // classes whose reflected calls return checked values.
2199
+ if (mapped?.kind === "union" && !hasExplicitJsDocReturn(info.decl) &&
2200
+ lowerer.unions.get(mapped.unionId)?.arms.some((arm) => arm.kind === "func"))
2201
+ return null;
2202
+ if (mapped?.kind === "symbol" && !hasExplicitJsDocReturn(info.decl))
2203
+ return null;
2204
+ if (mapped?.kind === "date" && !hasExplicitJsDocReturn(info.decl))
2205
+ return DYN;
2206
+ if (!hasExplicitJsDocReturn(info.decl) && info.decl.body) {
2207
+ let openReturn = false;
2208
+ ts.walkPreorder(info.decl.body, (node) => {
2209
+ if (node !== info.decl.body && ts.isFunctionLike(node))
2210
+ return "skip";
2211
+ if (!ts.isReturnStatement(node) || !node.expression || !ts.isIdentifier(node.expression))
2212
+ return undefined;
2213
+ const symbol = lowerer.resolveValueSymbol(node.expression);
2214
+ if (symbol && lowerer.checker.declarationsOf(symbol).some((decl) => ts.isVariableDeclaration(decl) && jsBindingHasOpenWrites(lowerer, decl)))
2215
+ openReturn = true;
2216
+ return undefined;
2217
+ });
2218
+ if (openReturn)
2219
+ return null;
2220
+ }
2221
+ // A JavaScript result inferred from an initial record can later
2222
+ // carry additional fields. Settle its representation from the
2223
+ // lowered returns instead of copying it back into that initial shape.
2224
+ const resultArms = mapped?.kind === "union" ? lowerer.unions.get(mapped.unionId)?.arms : mapped ? [mapped] : [];
2225
+ if (resultArms?.some((arm) => arm.kind === "record" || arm.kind === "object" || arm.kind === "classval") &&
2226
+ resultArms.every((arm) => isUnitType(arm) || arm.kind === "record" || arm.kind === "object" || arm.kind === "classval") &&
2227
+ !hasExplicitJsDocReturn(info.decl))
2228
+ return null;
2079
2229
  // Inferred variadic results carry runtime argument packs. Their
2080
2230
  // factory must retain the lowered callable rather than extracting a
2081
2231
  // fixed native signature from a checked value.
@@ -2117,15 +2267,52 @@ function bindableImplicitIr(t) {
2117
2267
  function storedImplicitArgumentType(lowerer, arg) {
2118
2268
  while (ts.isParenthesizedExpression(arg))
2119
2269
  arg = arg.expression;
2270
+ if (isJsSourceFile(arg.getSourceFile()) && (ts.isArrowFunction(arg) || ts.isFunctionExpression(arg))) {
2271
+ const saved = lowerer.diagSink;
2272
+ const diagnostics = [];
2273
+ lowerer.diagSink = diagnostics;
2274
+ let value;
2275
+ try {
2276
+ value = tryLowerExpression(lowerer, arg);
2277
+ }
2278
+ finally {
2279
+ lowerer.diagSink = saved;
2280
+ }
2281
+ // Direct inferred helpers can receive native callbacks even when their
2282
+ // result is an opaque handle that cannot cross checked storage.
2283
+ if (diagnostics.length === 0 && value?.type.kind === "func")
2284
+ return value.type;
2285
+ }
2286
+ if (arg.kind === ts.SyntaxKind.ThisKeyword)
2287
+ return lowerer.resolveThis()?.type ?? null;
2120
2288
  if (ts.isAwaitExpression(arg)) {
2121
2289
  const awaited = storedImplicitArgumentType(lowerer, arg.expression);
2122
2290
  return awaited?.kind === "promise" ? awaited.inner : awaited;
2123
2291
  }
2124
- if (ts.isObjectLiteralExpression(arg) && isJsSourceFile(arg.getSourceFile()) && arg.properties.some((property) => !ts.isSpreadAssignment(property) && property.name !== undefined && ts.isComputedPropertyName(property.name) &&
2125
- lowerer.foldedStringKeyOf(property.name.expression) === null))
2292
+ if (ts.isObjectLiteralExpression(arg) && isJsSourceFile(arg.getSourceFile()) &&
2293
+ (arg.properties.length === 0 || arg.properties.some((property) => ts.isMethodDeclaration(property) || ts.isAccessor(property) ||
2294
+ !ts.isSpreadAssignment(property) && property.name !== undefined && ts.isComputedPropertyName(property.name))))
2126
2295
  return DYN;
2127
2296
  if (ts.isIdentifier(arg))
2128
2297
  return lowerer.peekLocal(arg)?.type ?? lowerer.globalOf(arg)?.type ?? null;
2298
+ if (isJsSourceFile(arg.getSourceFile()) &&
2299
+ (ts.isPropertyAccessExpression(arg) || ts.isElementAccessExpression(arg))) {
2300
+ // Mutable JS members can retain an initializer-only checker type (for
2301
+ // example a linked-list slot initially null). Specialize to the value
2302
+ // we actually represent, rather than checking it back into that type.
2303
+ const represented = tryLowerExpression(lowerer, arg);
2304
+ if (represented)
2305
+ return represented.type;
2306
+ }
2307
+ if (isJsSourceFile(arg.getSourceFile()) && (ts.isCallExpression(arg) || ts.isConditionalExpression(arg) ||
2308
+ ts.isBinaryExpression(arg) && (arg.operatorToken.kind === ts.SyntaxKind.BarBarToken ||
2309
+ arg.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken || arg.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken))) {
2310
+ // Calls and fallback expressions can retain checked storage wider than
2311
+ // the checker's inference (for example Object.assign on a JS instance).
2312
+ const represented = tryLowerExpression(lowerer, arg);
2313
+ if (represented?.type.kind === "dyn" || represented?.type.kind === "func")
2314
+ return represented.type;
2315
+ }
2129
2316
  if (ts.isCallExpression(arg) && ts.isIdentifier(arg.expression)) {
2130
2317
  const callee = storedImplicitArgumentType(lowerer, arg.expression);
2131
2318
  if (callee?.kind === "dyn")
@@ -2173,12 +2360,29 @@ export function implicitCallInstance(lowerer, call, info) {
2173
2360
  shapes.push({ type: stored, mode: "required" });
2174
2361
  return;
2175
2362
  }
2363
+ if (stored?.kind === "func") {
2364
+ // The lowered closure may have an inferred JS destructuring
2365
+ // parameter widened from the checker's exact tuple to dyn.
2366
+ // Preserve that signature throughout the specialization.
2367
+ const checkerType = lowerer.mapTypeOf(lowerer.typeOf(arg));
2368
+ argTypes.set(sym, checkerType && typeEquals(checkerType, stored)
2369
+ ? lowerer.typeOf(arg) : lowerer.checker.getUnknownType());
2370
+ shapes.push({ type: stored, mode: "required" });
2371
+ return;
2372
+ }
2176
2373
  // The argument's own checker type, literal-widened ('add' binds
2177
2374
  // string) — typeOf consults the ACTIVE instance's bindings, so a
2178
2375
  // bound param forwarded into another implicit call transitively
2179
2376
  // instantiates it (this._initCommandGroup(command)).
2180
2377
  const t = lowerer.checker.getBaseTypeOfLiteralType(lowerer.typeOf(arg));
2181
- const mapped = lowerer.mapTypeOf(t) ?? dynFallbackType(lowerer, arg, t);
2378
+ const mapped = (neverTaintedJsType(lowerer, arg, t) ? null : lowerer.mapTypeOf(t)) ?? dynFallbackType(lowerer, arg, t);
2379
+ if (isJsSourceFile(arg.getSourceFile()) && ts.isArrayLiteralExpression(arg) && mapped?.kind === "array" &&
2380
+ (mapped.elem.kind === "classval" || mapped.elem.kind === "union" &&
2381
+ lowerer.unions.get(mapped.elem.unionId)?.arms.every((arm) => arm.kind === "classval"))) {
2382
+ argTypes.set(sym, lowerer.checker.getUnknownType());
2383
+ shapes.push({ type: DYN, mode: "required" });
2384
+ return;
2385
+ }
2182
2386
  // JavaScript arguments-based callables travel as checked functions.
2183
2387
  // Specializing a parameter to the inferred rest signature would
2184
2388
  // require extracting a native variadic ABI that the value does not
@@ -2192,6 +2396,11 @@ export function implicitCallInstance(lowerer, call, info) {
2192
2396
  // That checker supertype is not an empty-record runtime layout:
2193
2397
  // preserve represented arms through the checked boundary instead
2194
2398
  // of specializing a call to a union that would discard them.
2399
+ if (isJsSourceFile(arg.getSourceFile()) && mapped?.kind === "func" && !lowerer.dynConvertible(mapped)) {
2400
+ argTypes.set(sym, lowerer.checker.getUnknownType());
2401
+ shapes.push({ type: DYN, mode: "required" });
2402
+ return;
2403
+ }
2195
2404
  const mappedArms = mapped?.kind === "union" ? lowerer.unions.get(mapped.unionId)?.arms ?? [] : mapped ? [mapped] : [];
2196
2405
  const hasTopObject = mappedArms.some((arm) => {
2197
2406
  const shape = arm.kind === "record" ? lowerer.shapes.get(arm.shapeId) : undefined;
@@ -2737,7 +2946,15 @@ export function lowerTimersMemberCall(lowerer, expr, member, loc) {
2737
2946
  if (expr.arguments.length !== 1) {
2738
2947
  lowerer.noLowering(`clearTimeout with ${expr.arguments.length} arguments`, expr);
2739
2948
  }
2740
- const handle = lowerer.lowerExpr(expr.arguments[0]);
2949
+ let handle = lowerer.lowerExpr(expr.arguments[0]);
2950
+ if (handle.type.kind === "dyn" && isJsSourceFile(expr.getSourceFile())) {
2951
+ const stored = lowerer.declareHiddenLocal("%timer.clear", DYN);
2952
+ const ref = varRef(stored.id, DYN, loc);
2953
+ handle = { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: stored.id, init: handle, loc }], result: {
2954
+ kind: "ternary", cond: { kind: "dynTest", test: "number", value: ref, type: BOOL, loc },
2955
+ then: lowerer.coerceInto(expr.arguments[0], ref, F64), else_: numLit(0, loc), type: F64, loc,
2956
+ }, type: F64, loc };
2957
+ }
2741
2958
  if (handle.type.kind !== "f64") {
2742
2959
  lowerer.noLowering(`clearTimeout of '${lowerer.fmt(handle.type)}' handles`, expr.arguments[0], "the handle is the Timeout setTimeout returned (narrow 'Timeout | null' first)");
2743
2960
  }
@@ -3264,6 +3481,14 @@ function lowerProjectedBuiltinCall(lowerer, expr, bi, loc) {
3264
3481
  }
3265
3482
  export function lowerCall(lowerer, expr) {
3266
3483
  const loc = locOf(expr);
3484
+ // Object's checker return type is `any`. Claim known object inputs
3485
+ // before generic checked-dynamic dispatch tries to load the constructor.
3486
+ if (ts.isIdentifier(expr.expression) && expr.expression.text === "Object" &&
3487
+ lowerer.isStdlibGlobal(expr.expression, "Object")) {
3488
+ const object = lowerObjectConstructor(lowerer, expr.arguments, loc);
3489
+ if (object)
3490
+ return object;
3491
+ }
3267
3492
  // A call whose chain ROOTS at an ambient-undefined name (`declare
3268
3493
  // const value: Y | undefined; value?.foo("a")`, `declare function
3269
3494
  // chain...; chain(o).mapValues(f).value()`, a trap binding's read):
@@ -3373,7 +3598,7 @@ export function lowerCall(lowerer, expr) {
3373
3598
  // `a?.m()` (the token on the member access). The handled markers keep
3374
3599
  // the chain lowering's re-entrant dispatch from looping.
3375
3600
  if ((expr.questionDotToken && !lowerer.chainHandled.has(expr)) ||
3376
- (ts.isPropertyAccessExpression(expr.expression) &&
3601
+ ((ts.isPropertyAccessExpression(expr.expression) || ts.isElementAccessExpression(expr.expression)) &&
3377
3602
  expr.expression.questionDotToken &&
3378
3603
  !lowerer.chainHandled.has(expr.expression))) {
3379
3604
  return lowerer.lowerOptionalChain(expr);
@@ -3382,6 +3607,9 @@ export function lowerCall(lowerer, expr) {
3382
3607
  // top-level statement (its field-initializer ordering lives there);
3383
3608
  // any other position would misorder initialization — rejected.
3384
3609
  if (expr.expression.kind === ts.SyntaxKind.SuperKeyword) {
3610
+ const superCall = lowerer.ctx.superCall;
3611
+ if (superCall)
3612
+ return superCall(expr);
3385
3613
  lowerer.unsupported("SC1090", expr, "super() calls anywhere but as a top-level constructor statement");
3386
3614
  }
3387
3615
  // super.method(...): a DIRECT (never virtual) call of the base chain's
@@ -3500,6 +3728,13 @@ export function lowerCall(lowerer, expr) {
3500
3728
  loc,
3501
3729
  });
3502
3730
  }
3731
+ if (ts.isPropertyAccessExpression(expr.expression) &&
3732
+ TIMER_MODULE_MEMBERS.has(expr.expression.name.text) &&
3733
+ lowerer.stdlibGlobalMember(expr.expression, "globalThis") === expr.expression.name.text) {
3734
+ const served = lowerTimersMemberCall(lowerer, expr, expr.expression.name.text, loc);
3735
+ if (served)
3736
+ return served;
3737
+ }
3503
3738
  // The timer globals — setTimeout/clearTimeout, setInterval/
3504
3739
  // clearInterval, setImmediate/clearImmediate. Provenance-checked (a
3505
3740
  // user function shadowing the name has a different, non-ambient
@@ -3642,9 +3877,7 @@ export function lowerCall(lowerer, expr) {
3642
3877
  // Provenance-checked like setTimeout; zero-arg forms are the JS
3643
3878
  // constants ("", false, 0). Wrapper objects stay fenced except where
3644
3879
  // the receiver is immediately converted by a direct String method call.
3645
- if (ts.isIdentifier(expr.expression) &&
3646
- expr.expression.text === "BigInt" &&
3647
- lowerer.isStdlibSymbol(lowerer.resolveValueSymbol(expr.expression) ?? undefined)) {
3880
+ if (lowerer.isStdlibGlobal(expr.expression, "BigInt")) {
3648
3881
  if (expr.arguments.length !== 1) {
3649
3882
  lowerer.noLowering(`BigInt with ${expr.arguments.length} arguments`, expr);
3650
3883
  }
@@ -3657,12 +3890,11 @@ export function lowerCall(lowerer, expr) {
3657
3890
  return converted;
3658
3891
  lowerer.noLowering(`BigInt of ${lowerer.fmt(arg.type)} values`, argNode, "string, number, boolean, and bigint arguments are supported");
3659
3892
  }
3660
- if (ts.isIdentifier(expr.expression) &&
3661
- (expr.expression.text === "String" ||
3662
- expr.expression.text === "Boolean" ||
3663
- expr.expression.text === "Number") &&
3664
- lowerer.isStdlibSymbol(lowerer.resolveValueSymbol(expr.expression) ?? undefined)) {
3665
- const name = expr.expression.text;
3893
+ if (lowerer.isStdlibGlobal(expr.expression, "String") ||
3894
+ lowerer.isStdlibGlobal(expr.expression, "Boolean") ||
3895
+ lowerer.isStdlibGlobal(expr.expression, "Number")) {
3896
+ const name = lowerer.isStdlibGlobal(expr.expression, "String") ? "String" :
3897
+ lowerer.isStdlibGlobal(expr.expression, "Boolean") ? "Boolean" : "Number";
3666
3898
  if (expr.arguments.length > 1) {
3667
3899
  lowerer.noLowering(`${name} with ${expr.arguments.length} arguments`, expr);
3668
3900
  }
@@ -3692,8 +3924,9 @@ export function lowerCall(lowerer, expr) {
3692
3924
  if (name === "Number")
3693
3925
  return lowerNumberConstructorValue(lowerer, argNode, loc);
3694
3926
  const arg = lowerer.lowerExpr(argNode);
3695
- if (name === "String" && arg.type.kind === "dyn") {
3696
- return { kind: "libCall", fn: "dyn.stringConstructor", args: [arg], type: STRING, loc };
3927
+ if (name === "String" && (arg.type.kind === "dyn" || arg.type.kind === "union" &&
3928
+ lowerer.unions.get(arg.type.unionId)?.arms.some((arm) => arm.kind === "symbol") && lowerer.dynConvertible(arg.type))) {
3929
+ return { kind: "libCall", fn: "dyn.stringConstructor", args: [lowerer.coerceToExpected(arg, DYN)], type: STRING, loc };
3697
3930
  }
3698
3931
  if (name === "String")
3699
3932
  return lowerer.ensureString(arg, argNode);
@@ -3720,7 +3953,9 @@ export function lowerCall(lowerer, expr) {
3720
3953
  lowerer.fenceStaticHeadersMember(access, "call");
3721
3954
  lowerer.fenceStaticReadableStreamMember(access, "call");
3722
3955
  const source = tryLowerExpression(lowerer, access.expression);
3723
- if (source && (source.type.kind === "dyn" || isDynTypedRefType(source.type) &&
3956
+ if (source && (source.type.kind === "dyn" || source.type.kind === "func" ||
3957
+ source.type.kind === "union" && isJsSourceFile(expr.getSourceFile()) && lowerer.dynConvertible(source.type) ||
3958
+ (source.type.kind === "map" || source.type.kind === "set") && lowerer.dynConvertible(source.type) || isDynTypedRefType(source.type) &&
3724
3959
  lowerer.foldedStringKeyOf(access.argumentExpression) === null &&
3725
3960
  lowerer.mapTypeOf(lowerer.typeOf(access.argumentExpression))?.kind !== "symbol")) {
3726
3961
  const local = lowerer.declareHiddenLocal("%computedReceiver", DYN);
@@ -4106,6 +4341,9 @@ export function lowerCall(lowerer, expr) {
4106
4341
  if (name === "parseFloat" && probed?.type.kind === "string") {
4107
4342
  return { kind: "libCall", fn: "num.parseFloat", args: [probed], type: F64, loc };
4108
4343
  }
4344
+ if (name === "parseFloat" && probed?.type.kind === "dyn") {
4345
+ return { kind: "libCall", fn: "num.parseFloat", args: [{ kind: "libCall", fn: "dyn.toStringCoerce", args: [probed], type: STRING, loc }], type: F64, loc };
4346
+ }
4109
4347
  if (name === "isFinite" && probed?.type.kind === "f64") {
4110
4348
  return { kind: "libCall", fn: "number.isFinite", args: [probed], type: BOOL, loc };
4111
4349
  }
@@ -4123,6 +4361,7 @@ export function lowerCall(lowerer, expr) {
4123
4361
  // string-only argument rule.
4124
4362
  if ((expr.expression.text === "encodeURIComponent" ||
4125
4363
  expr.expression.text === "encodeURI" ||
4364
+ expr.expression.text === "decodeURI" ||
4126
4365
  expr.expression.text === "decodeURIComponent") &&
4127
4366
  lowerer.isStdlibSymbol(lowerer.resolveValueSymbol(expr.expression) ?? undefined)) {
4128
4367
  const name = expr.expression.text;
@@ -4131,10 +4370,10 @@ export function lowerCall(lowerer, expr) {
4131
4370
  }
4132
4371
  const loc = locOf(expr);
4133
4372
  const argNode = expr.arguments[0];
4134
- if (name === "decodeURIComponent") {
4373
+ if (name === "decodeURIComponent" || name === "decodeURI") {
4135
4374
  const d = optionalCallValue(lowerer, argNode) ?? lowerer.lowerExpr(argNode);
4136
4375
  const s = lowerer.ensureString(d, argNode);
4137
- return { kind: "libCall", fn: "str.decodeUriComponent", args: [s], type: STRING, loc };
4376
+ return { kind: "libCall", fn: name === "decodeURI" ? "str.decodeUri" : "str.decodeUriComponent", args: [s], type: STRING, loc };
4138
4377
  }
4139
4378
  const value = optionalCallValue(lowerer, argNode) ?? lowerer.lowerExpr(argNode);
4140
4379
  const s = lowerer.ensureString(value, argNode);
@@ -4415,7 +4654,8 @@ export function lowerCall(lowerer, expr) {
4415
4654
  lowerer.lowerJsonMethodCall(expr, expr.expression) ??
4416
4655
  // Reflect.apply of a builtin rest-parameter fn (fixtures.js's
4417
4656
  // fixturesPath idiom) — before the stdlib member fence claims it.
4418
- lowerReflectApplyCall(lowerer, expr, expr.expression) ??
4657
+ lowerReflectCall(lowerer, expr, expr.expression) ??
4658
+ lowerBigIntStaticCall(lowerer, expr, expr.expression) ??
4419
4659
  lowerer.lowerNumberStaticCall(expr, expr.expression) ??
4420
4660
  lowerer.lowerDateCall(expr, expr.expression) ??
4421
4661
  lowerer.lowerTextCodecCall(expr, expr.expression) ??
@@ -4431,6 +4671,7 @@ export function lowerCall(lowerer, expr) {
4431
4671
  // Before the island path: regex-argument replace/replaceAll/split
4432
4672
  // lower STATICALLY; only the string-pattern overloads are island.
4433
4673
  lowerRegexMethodCallWithOptionalArg(lowerer, expr, expr.expression) ??
4674
+ lowerUrlStaticCall(lowerer, expr, expr.expression) ??
4434
4675
  lowerer.lowerUrlMethodCall(expr, expr.expression) ??
4435
4676
  lowerer.lowerSearchParamsMethodCall(expr, expr.expression) ??
4436
4677
  lowerer.lowerStatsMethodCall(expr, expr.expression) ??
@@ -4481,14 +4722,11 @@ export function lowerCall(lowerer, expr) {
4481
4722
  lowerer.lowerBytesMethodCall(expr, expr.expression) ??
4482
4723
  lowerBytesStaticCall(lowerer, expr, expr.expression) ??
4483
4724
  lowerBufferStaticCallWithNarrowedArg(lowerer, expr, expr.expression) ??
4484
- // URL.revokeObjectURL's zero-argument contract (the one-argument
4485
- // form keeps the fence — createObjectURL does too).
4486
- lowerUrlStaticCall(lowerer, expr, expr.expression) ??
4487
4725
  // Readable.from — the stream classes' one static (before the
4488
4726
  // stdlib chokepoint claims the member).
4489
4727
  lowerStreamStaticCall(lowerer, expr, expr.expression) ??
4490
- // Radix-free n.toString() is the STATIC number formatter (identical
4491
- // to `${n}` / String(n)); the explicit-radix form stays island.
4728
+ // Primitive toString calls, including numeric radices, use the
4729
+ // native formatters before the island method path.
4492
4730
  lowerNumberToStringCall(lowerer, expr, expr.expression) ??
4493
4731
  // Union receivers whose every arm has a text — the ngrok
4494
4732
  // `(chunk: Buffer | string) => chunk.toString()` idiom.
@@ -4528,7 +4766,6 @@ export function lowerCall(lowerer, expr) {
4528
4766
  // by the receiver's own element.
4529
4767
  lowerer.lowerFilterNarrowCall(expr, expr.expression) ??
4530
4768
  lowerArrayIsArrayCall(lowerer, expr, expr.expression) ??
4531
- lowerBigIntStaticCall(lowerer, expr, expr.expression) ??
4532
4769
  lowerBigIntMethodCall(lowerer, expr, expr.expression) ??
4533
4770
  lowerSymbolStaticCall(lowerer, expr, expr.expression) ??
4534
4771
  lowerSymbolMethodCall(lowerer, expr, expr.expression) ??
@@ -4563,6 +4800,13 @@ export function lowerCall(lowerer, expr) {
4563
4800
  lowerObjLitGenericMethodCall(lowerer, expr, expr.expression);
4564
4801
  if (intrinsic)
4565
4802
  return intrinsic;
4803
+ if (isJsSourceFile(expr.getSourceFile())) {
4804
+ const staticField = lowerStaticFieldRead(lowerer, expr.expression);
4805
+ if (staticField?.type.kind === "dyn" && !expr.arguments.some(ts.isSpreadElement)) {
4806
+ return { kind: "dynCall", callee: staticField, receiver: lowerer.lowerExprExpecting(expr.expression.expression, DYN), calleeName: expr.expression.getText(),
4807
+ args: expr.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc: locOf(expr) };
4808
+ }
4809
+ }
4566
4810
  const accessorTarget = lowerer.fieldTarget(expr.expression);
4567
4811
  if (accessorTarget?.container === "accessor") {
4568
4812
  const callee = lowerer.fieldGetExpr(accessorTarget, locOf(expr.expression), expr.expression);
@@ -4635,6 +4879,30 @@ export function lowerCall(lowerer, expr) {
4635
4879
  lowerer.fenceStaticHeadersMember(expr.expression, "call");
4636
4880
  lowerer.fenceStaticReadableStreamMember(expr.expression, "call");
4637
4881
  }
4882
+ // Computed native members retain their original receiver and resolve
4883
+ // the function before argument effects, just like dotted calls.
4884
+ if (ts.isElementAccessExpression(expr.expression) && !expr.expression.questionDotToken && !expr.questionDotToken &&
4885
+ !symbolFieldInfo(lowerer, expr.expression)) {
4886
+ const access = expr.expression;
4887
+ const value = tryLowerExpression(lowerer, access.expression);
4888
+ if (value?.type.kind === "dyn" || value?.type.kind === "generator" ||
4889
+ value && ["array", "bytes", "map", "set"].includes(value.type.kind) && lowerer.dynConvertible(value.type) ||
4890
+ value?.type.kind === "string" && !ts.isStringLiteralLike(access.argumentExpression) && lowerer.dynConvertible(value.type) ||
4891
+ value?.type.kind === "object" && !lowerer.classes.get(value.type.className)?.def.runtime) {
4892
+ const local = lowerer.declareHiddenLocal("%computedReceiver", value.type);
4893
+ const reference = { kind: "varRef", localId: local.id, type: value.type, loc };
4894
+ const receiver = lowerer.coerceToExpected(reference, DYN);
4895
+ const raw = lowerer.lowerExpr(access.argumentExpression);
4896
+ const key = raw.type.kind === "string" ? raw : lowerer.coerceInto(access.argumentExpression, raw, DYN);
4897
+ const callee = { kind: "dynKeyGet", value: receiver, key, type: DYN, loc };
4898
+ const spread = expr.arguments.some(ts.isSpreadElement) ? lowerSpreadArgsCall(lowerer, expr, callee, loc) : null;
4899
+ if (spread && spread.kind !== "dynCall")
4900
+ lowerer.unsupported("SC1090", expr, "computed native method spread arguments");
4901
+ const result = spread !== null ? { ...spread, receiver } : { kind: "dynCall", callee, receiver,
4902
+ calleeName: access.getText(), args: expr.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
4903
+ return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id, init: value, loc }], result, type: DYN, loc };
4904
+ }
4905
+ }
4638
4906
  // The ELEMENT spelling of a primitive method call — `x['toString']()`,
4639
4907
  // `s['charAt'](0)`: JS resolves it exactly like the dot form, so the
4640
4908
  // literal-keyed shapes with a static lowering route there before the
@@ -4720,6 +4988,11 @@ export function lowerCall(lowerer, expr) {
4720
4988
  : "value";
4721
4989
  return { kind: "dynCall", callee, calleeName, args, type: DYN, loc };
4722
4990
  }
4991
+ if (callee.type.kind === "union" && lowerer.dynConvertible(callee.type) &&
4992
+ lowerer.unions.get(callee.type.unionId)?.arms.some((arm) => arm.kind === "func")) {
4993
+ return { kind: "dynCall", callee: lowerer.coerceToExpected(callee, DYN), calleeName: expr.expression.getText(),
4994
+ args: expr.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
4995
+ }
4723
4996
  if (callee.type.kind !== "func") {
4724
4997
  lowerer.badType(expr.expression, lowerer.typeOf(expr.expression));
4725
4998
  }
@@ -4959,6 +5232,10 @@ function lowerNumberConstructorValue(lowerer, argNode, loc) {
4959
5232
  return { kind: "libCall", fn: "num.fromString", args: [arg], type: F64, loc };
4960
5233
  if (arg.type.kind === "dyn")
4961
5234
  return { kind: "libCall", fn: "dyn.numberConstructor", args: [arg], type: F64, loc };
5235
+ if (arg.type.kind === "union" && lowerer.dynConvertible(arg.type))
5236
+ return {
5237
+ kind: "libCall", fn: "dyn.numberConstructor", args: [lowerer.coerceToExpected(arg, DYN)], type: F64, loc,
5238
+ };
4962
5239
  const optionalNumber = lowerOptionalStringNumber(lowerer, arg, loc);
4963
5240
  if (optionalNumber)
4964
5241
  return optionalNumber;
@@ -4973,6 +5250,8 @@ function lowerNumberConstructorValue(lowerer, argNode, loc) {
4973
5250
  * checker guard. Dispatch BigInt by the actual value, including nullish
4974
5251
  * TypeErrors, rather than interpreting that storage as the narrowed arm. */
4975
5252
  function lowerBigIntConstructorValue(lowerer, arg, loc) {
5253
+ if (arg.type.kind === "dyn")
5254
+ return { kind: "libCall", fn: "dyn.bigintConstructor", args: [arg], type: BIGINT_T, loc };
4976
5255
  if (arg.type.kind === "bigint")
4977
5256
  return arg;
4978
5257
  if (arg.type.kind === "string")
@@ -5244,8 +5523,9 @@ function lowerObjectOwnCall(lowerer, call, receiverNode, keyNode, extraNodes, me
5244
5523
  stmts.push({ kind: "exprStmt", expr: effect, loc: locOf(extra) });
5245
5524
  }
5246
5525
  let key = keyRef;
5247
- if (receiverRef.type.kind === "dyn" && keyRef && (keyRef.type.kind === "symbol" || keyRef.type.kind === "dyn")) {
5248
- const result = { kind: "libCall", fn: enumerable ? "dyn.propertyIsEnumerableComputed" : "dyn.hasOwnComputed", args: [receiverRef, lowerer.coerceToExpected(keyRef, DYN)], type: BOOL, loc };
5526
+ if (lowerer.dynConvertible(receiverRef.type) && keyRef && (receiverRef.type.kind === "object" || keyRef.type.kind === "symbol" || keyRef.type.kind === "dyn" ||
5527
+ keyRef.type.kind === "union" && lowerer.dynConvertible(keyRef.type))) {
5528
+ const result = { kind: "libCall", fn: enumerable ? "dyn.propertyIsEnumerableComputed" : "dyn.hasOwnComputed", args: [lowerer.coerceToExpected(receiverRef, DYN), lowerer.coerceToExpected(keyRef, DYN)], type: BOOL, loc };
5249
5529
  return { kind: "seqExpr", stmts, result, type: BOOL, loc };
5250
5530
  }
5251
5531
  if (!keyNode || rawKey?.type.kind === "undefinedT" || rawKey?.type.kind === "void") {
@@ -5441,6 +5721,9 @@ function lowerStringPrototypeCall(lowerer, call, access) {
5441
5721
  // padding uses a helper that delays conversion until every argument is ready.
5442
5722
  const objectWithoutMethodArgs = entry?.maxArgs === 0 && call.arguments.length === 1 &&
5443
5723
  (receiverType.kind === "record" || receiverType.kind === "array" || receiverType.kind === "object");
5724
+ if (padding && !scalar && lowerer.dynConvertible(receiverType)) {
5725
+ return lowerStringPaddingCall(lowerer, call, entry.method, lowerer.coerceToExpected(receiverValue, DYN), receiverNode, call.arguments.slice(1));
5726
+ }
5444
5727
  if (!scalar && !objectWithoutMethodArgs) {
5445
5728
  lowerer.noLowering(`String.prototype.${methodAccess.name.text}.call with ${lowerer.fmt(receiverType)} receivers`, call);
5446
5729
  }
@@ -5581,7 +5864,7 @@ function lowerSpreadArgsCall(lowerer, expr, callee, loc) {
5581
5864
  // The spelling rides along for V8's nullish spread-call
5582
5865
  // TypeError ("v is not iterable (cannot read property ...)").
5583
5866
  spreads.push({ arg: args.length, what: p.spreadOf.getText() });
5584
- args.push(lowerer.coerceInto(p.spreadOf, p.v, DYN));
5867
+ args.push(checkedIterableSpread(lowerer, p.v, p.spreadOf.getText(), loc));
5585
5868
  }
5586
5869
  else {
5587
5870
  args.push(lowerer.coerceInto(p.node, p.v, DYN));
@@ -5591,7 +5874,7 @@ function lowerSpreadArgsCall(lowerer, expr, callee, loc) {
5591
5874
  return { kind: "dynCall", callee: boxed, calleeName, args, spreads, type: DYN, loc };
5592
5875
  }
5593
5876
  if (spreadParts.length > 0 &&
5594
- spreadParts.every((p) => p.v.type.kind === "jsval") &&
5877
+ (spreadParts.every((p) => p.v.type.kind === "jsval") || callee.type.kind === "func" && callee.type.restAbi === "jsval") &&
5595
5878
  (callee.type.kind === "jsval" || callee.type.kind === "func")) {
5596
5879
  if (spreadParts.length !== 1 || parts[parts.length - 1].spreadOf === null) {
5597
5880
  lowerer.unsupported("SC1090", expr, "spread arguments before positional arguments in island calls (one trailing spread after the fixed arguments is the supported form)");
@@ -5604,7 +5887,7 @@ function lowerSpreadArgsCall(lowerer, expr, callee, loc) {
5604
5887
  const last = parts[parts.length - 1];
5605
5888
  // The spelling rides in `name` for V8's nullish spread-call
5606
5889
  // TypeError ("v is not iterable (cannot read property ...)").
5607
- return { kind: "jsOp", op: "callSpread", name: last.spreadOf.getText(), args: [f, preArr, last.v], type: JSVAL, loc };
5890
+ return { kind: "jsOp", op: "callSpread", name: last.spreadOf.getText(), args: [f, preArr, lowerer.coerceInto(last.spreadOf, last.v, JSVAL)], type: JSVAL, loc };
5608
5891
  }
5609
5892
  // No lane fits (a spread source outside both tiers, a callee neither
5610
5893
  // boxable nor marshalable, mixed dyn/jsval spreads): fence HERE — the
@@ -5656,12 +5939,21 @@ function canCompleteRuntimeSpread(lowerer, shapes) {
5656
5939
  function lowerDynReceiverMethodCall(lowerer, call, access) {
5657
5940
  if (lowerer.chainBlocked(call, access))
5658
5941
  return null;
5942
+ if (stdlibGlobalNameOf(lowerer, access.expression) !== null)
5943
+ return null;
5659
5944
  // Only checker-untyped receivers: `any`/`unknown`, or the `any[]` an
5660
5945
  // Array.isArray guard narrows them to (the value is STILL the checked-dynamic tree
5661
5946
  // array — scalar narrowings bridge through maybeNarrow's dynCheck and
5662
5947
  // take the ordinary typed paths, but there is no static home for an
5663
5948
  // any-elemented array). Typed receivers keep their own lowerings.
5664
5949
  const recvTs = lowerer.typeOf(access.expression);
5950
+ const recvSymbol = recvTs.getSymbol();
5951
+ if (recvSymbol && ["MapIterator", "SetIterator"].includes(recvSymbol.name) &&
5952
+ lowerer.isStdlibSymbol(recvSymbol) &&
5953
+ ["map", "filter", "take", "drop", "flatMap", "toArray", "forEach", "reduce", "some", "every", "find"].includes(access.name.text) &&
5954
+ lowerer.isStdlibMember(access)) {
5955
+ lowerer.noLowering(`collection iterator .${access.name.text}()`, call, "stored Map/Set iterators support .next() and iteration; iterator helper methods have no lowering");
5956
+ }
5665
5957
  const arrayReceiver = lowerer.checker.isArrayType(recvTs);
5666
5958
  const anyArray = arrayReceiver &&
5667
5959
  ((lowerer.checker.getTypeArguments(recvTs)[0]?.flags ?? 0) &
@@ -5677,11 +5969,11 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
5677
5969
  // tsc types the return by the evolved shape, the binding lowered
5678
5970
  // dyn): probe the lowering and claim exactly the dyn results.
5679
5971
  const probed = tryLowerExpression(lowerer, access.expression);
5680
- if (isJsSourceFile(call.getSourceFile()) && probed?.type.kind === "func" &&
5972
+ if (probed?.type.kind === "func" && stdlibGlobalNameOf(lowerer, access.expression) === null &&
5681
5973
  !["call", "apply", "bind", "toString", "valueOf", "constructor"].includes(access.name.text) &&
5682
5974
  canBoxFuncIntoDyn(probed.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
5683
5975
  const loc = locOf(call);
5684
- const fnName = jsFuncNameOf(access.expression);
5976
+ const fnName = jsFuncNameOf(access.expression, lowerer);
5685
5977
  const boxed = { kind: "dynFrom", value: probed, type: DYN, loc, ...(fnName !== null ? { fnName } : {}) };
5686
5978
  const local = lowerer.declareHiddenLocal("%callableReceiver", DYN);
5687
5979
  const receiver = { kind: "varRef", localId: local.id, type: DYN, loc };
@@ -5698,9 +5990,27 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
5698
5990
  args: call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc }, type: DYN, loc,
5699
5991
  };
5700
5992
  }
5701
- if (probed?.type.kind !== "dyn")
5702
- return null;
5703
- recv = probed;
5993
+ if (probed?.type.kind === "classval") {
5994
+ const info = lowerer.classes.get(probed.type.className);
5995
+ if (info)
5996
+ return lowerStaticMethodCall(lowerer, call, access);
5997
+ }
5998
+ if (probed?.type.kind === "union" && isJsSourceFile(call.getSourceFile()) &&
5999
+ lowerer.unions.get(probed.type.unionId)?.arms.every((arm) => isUnitType(arm) || arm.kind === "object" || arm.kind === "record" || arm.kind === "func") && lowerer.dynConvertible(probed.type)) {
6000
+ recv = lowerer.coerceToExpected(probed, DYN);
6001
+ }
6002
+ else {
6003
+ if (probed?.type.kind !== "dyn")
6004
+ return null;
6005
+ recv = probed;
6006
+ }
6007
+ }
6008
+ // A factory may return a constructor more precise than its inferred
6009
+ // checker result. Runtime static members live on that constructor.
6010
+ if (recv.type.kind === "classval") {
6011
+ const info = lowerer.classes.get(recv.type.className);
6012
+ if (info)
6013
+ return lowerStaticMethodCall(lowerer, call, access);
5704
6014
  }
5705
6015
  // A checker-`any` receiver that already lowered to a real STRING (the
5706
6016
  // chained form — `cfg.host.trim().toLowerCase()`, where the first step
@@ -5715,6 +6025,25 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
5715
6025
  }
5716
6026
  if (recv.type.kind !== "dyn")
5717
6027
  return null;
6028
+ if (access.name.text === "normalize" && call.arguments.length <= 1 && !call.arguments.some(ts.isSpreadElement)) {
6029
+ const loc = locOf(call);
6030
+ const hasArgument = call.arguments.length === 1;
6031
+ const name = `%dyn.string.normalize:${hasArgument ? 1 : 0}`;
6032
+ if (!lowerer.liftedFns.some((fn) => fn.name === name)) {
6033
+ const value = varRef("receiver", DYN, loc);
6034
+ const argument = varRef("form", DYN, loc);
6035
+ const form = { kind: "ternary", cond: { kind: "dynTest", value: argument, test: "undefined", type: BOOL, loc },
6036
+ then: { kind: "strLit", value: "NFC", type: STRING, loc },
6037
+ else_: { kind: "libCall", fn: "dyn.toStringCoerce", args: [argument], type: STRING, loc }, type: STRING, loc };
6038
+ const result = { kind: "strIntrinsic", method: "normalize", receiver: { kind: "dynCheck", value, type: STRING, loc }, args: [form], type: STRING, loc };
6039
+ lowerer.liftedFns.push({ name, params: [{ localId: "receiver", name: "receiver", type: DYN }, { localId: "form", name: "form", type: DYN }],
6040
+ locals: [{ id: "receiver", name: "receiver", type: DYN, mutable: false }, { id: "form", name: "form", type: DYN, mutable: false }], returnType: DYN, loc,
6041
+ body: [{ kind: "if", cond: { kind: "dynTest", value, test: "string", type: BOOL, loc }, then: [
6042
+ { kind: "return", value: { kind: "dynFrom", value: result, type: DYN, loc }, loc },
6043
+ ], else_: null, loc }, { kind: "return", value: { kind: "dynInvoke", recv: value, method: "normalize", calleeName: access.getText(), args: hasArgument ? [argument] : [], type: DYN, loc }, loc }] });
6044
+ }
6045
+ return { kind: "call", callee: name, args: [recv, call.arguments[0] ? lowerer.lowerExprExpecting(call.arguments[0], DYN) : dynUndefinedExpr(loc)], type: DYN, loc };
6046
+ }
5718
6047
  if (lowerer.mapTypeOf(recvTs)?.kind === "classval") {
5719
6048
  return lowerStaticMethodCall(lowerer, call, access);
5720
6049
  }
@@ -5770,7 +6099,16 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
5770
6099
  // unimplemented methods throw a LOUD not-supported Error; names the
5771
6100
  // kind's prototype lacks throw Node's "x.y is not a function"; OBJ
5772
6101
  // receivers call the own member.
5773
- const dispatched = lowerDynDispatchMethodCall(lowerer, call, access, recv, arrayReceiver);
6102
+ // A stored callback must be read before argument effects, and called
6103
+ // with the original receiver rather than a materialized property view.
6104
+ const callbackProperty = (() => {
6105
+ const prop = lowerer.checker.getPropertyOfType(recvTs, access.name.text);
6106
+ const mapped = lowerer.mapTypeOf(recvTs);
6107
+ if (mapped?.kind === "union" && lowerer.unions.get(mapped.unionId)?.arms.every((arm) => arm.kind === "object" && lowerer.classes.get(arm.className)?.fields.has(access.name.text)))
6108
+ return true;
6109
+ return prop !== undefined && lowerer.checker.declarationsOf(prop).some((decl) => ts.isPropertyDeclaration(decl) || ts.isPropertySignature(decl));
6110
+ })();
6111
+ const dispatched = callbackProperty ? null : lowerDynDispatchMethodCall(lowerer, call, access, recv, arrayReceiver);
5774
6112
  if (dispatched)
5775
6113
  return dispatched;
5776
6114
  // Names NO dyn-representable prototype declares: the member can only
@@ -5796,9 +6134,6 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
5796
6134
  if (call.questionDotToken || access.questionDotToken)
5797
6135
  return null;
5798
6136
  const loc = locOf(call);
5799
- if (call.arguments.some((a) => ts.isSpreadElement(a))) {
5800
- lowerer.unsupported("SC1090", call, "spread arguments in calls through 'unknown' values");
5801
- }
5802
6137
  const receiverLocal = lowerer.declareHiddenLocal("%dynCallReceiver", DYN);
5803
6138
  const receiver = { kind: "varRef", localId: receiverLocal.id, type: DYN, loc };
5804
6139
  const member = {
@@ -5808,10 +6143,24 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
5808
6143
  type: DYN,
5809
6144
  loc: locOf(access),
5810
6145
  };
6146
+ const calleeLocal = lowerer.declareHiddenLocal("%dynCallCallee", DYN);
6147
+ const callee = varRef(calleeLocal.id, DYN, loc);
6148
+ const stmts = [
6149
+ { kind: "varDecl", localId: receiverLocal.id, init: recv, loc },
6150
+ { kind: "varDecl", localId: calleeLocal.id, init: member, loc },
6151
+ ];
6152
+ if (call.arguments.some(ts.isSpreadElement)) {
6153
+ const spread = lowerSpreadArgsCall(lowerer, call, callee, loc);
6154
+ if (spread?.kind === "dynCall")
6155
+ return { kind: "seqExpr",
6156
+ stmts,
6157
+ result: { ...spread, receiver }, type: DYN, loc };
6158
+ lowerer.unsupported("SC1090", call, "spread arguments in calls through 'unknown' values");
6159
+ }
5811
6160
  const args = call.arguments.map((a) => lowerer.lowerExprExpecting(a, DYN));
5812
6161
  return {
5813
- kind: "seqExpr", stmts: [{ kind: "varDecl", localId: receiverLocal.id, init: recv, loc }],
5814
- result: { kind: "dynCall", callee: member, receiver, calleeName: access.getText(), args, type: DYN, loc }, type: DYN, loc,
6162
+ kind: "seqExpr", stmts,
6163
+ result: { kind: "dynCall", callee, receiver, calleeName: access.getText(), args, type: DYN, loc }, type: DYN, loc,
5815
6164
  };
5816
6165
  }
5817
6166
  /** Prototype method names of the checked-dynamic tree-representable kinds (String, Array,
@@ -5839,6 +6188,7 @@ const DYN_PROTO_METHOD_NAMES = new Set([
5839
6188
  * is-not-a-function where the kind's prototype lacks the name, and
5840
6189
  * fences LOUDLY on real-but-unimplemented pairs. */
5841
6190
  const DYN_DISPATCH_METHODS = new Set([
6191
+ "toFixed", "toExponential",
5842
6192
  "segment", "containing", "resolvedOptions", "test", "exec",
5843
6193
  "apply", "bind", "call",
5844
6194
  "push", "pop", "shift", "unshift", "slice", "at",
@@ -5858,7 +6208,7 @@ const DYN_DISPATCH_METHODS = new Set([
5858
6208
  "setEncoding", "setDefaultEncoding", "setTimeout", "read", "isPaused",
5859
6209
  "writeHead", "setHeader", "getHeader", "hasHeader", "removeHeader",
5860
6210
  "getHeaders", "getHeaderNames", "appendHeader", "flushHeaders",
5861
- "add", "append", "delete", "get", "getSetCookie", "has", "set",
6211
+ "add", "append", "delete", "get", "getSetCookie", "has", "set", "clear", "keys", "values", "entries", "next",
5862
6212
  "writeContinue", "writeEarlyHints", "cork", "uncork", "addTrailers",
5863
6213
  "ref", "unref", "address", "setNoDelay", "setKeepAlive", "connect",
5864
6214
  "resetAndDestroy", "destroySoon",
@@ -5879,7 +6229,7 @@ const DYN_DISPATCH_METHODS = new Set([
5879
6229
  "dispatchEvent",
5880
6230
  "preventDefault", "stopPropagation", "stopImmediatePropagation",
5881
6231
  "composedPath",
5882
- "json", "text", "bytes",
6232
+ "json", "text", "bytes", "arrayBuffer",
5883
6233
  // Promise.prototype (SCR_DYN_PROMISE receivers): the reaction trio
5884
6234
  // rides the fiber machinery (scr_dyn_promise_then); on every other dyn
5885
6235
  // kind then/catch/finally answer the stored-member path (OBJ own
@@ -5899,6 +6249,17 @@ export function lowerDynDispatchMethodCall(lowerer, call, access, recv, arrayRec
5899
6249
  if ((!DYN_DISPATCH_METHODS.has(method) && !isJsSourceFile(call.getSourceFile())) || lowerer.chainBlocked(call, access))
5900
6250
  return null;
5901
6251
  if (call.arguments.some((arg) => ts.isSpreadElement(arg))) {
6252
+ const loc = locOf(call);
6253
+ const local = lowerer.declareHiddenLocal("%spreadReceiver", DYN);
6254
+ const receiver = varRef(local.id, DYN, loc);
6255
+ const callee = { kind: "dynKeyGet", value: receiver,
6256
+ key: { kind: "strLit", value: method, type: STRING, loc }, type: DYN, loc };
6257
+ const spread = lowerSpreadArgsCall(lowerer, call, callee, loc);
6258
+ if (spread?.kind === "dynCall")
6259
+ return { kind: "seqExpr",
6260
+ stmts: [{ kind: "varDecl", localId: local.id, init: recv, loc },
6261
+ { kind: "exprStmt", expr: { kind: "libCall", fn: "dyn.arrayPrototype", args: [], type: DYN, loc }, loc }],
6262
+ result: { ...spread, receiver }, type: DYN, loc };
5902
6263
  lowerer.unsupported("SC1090", call, "spread arguments in calls through 'unknown' values");
5903
6264
  }
5904
6265
  const predicate = method === "filter" && call.arguments[0]
@@ -5972,7 +6333,12 @@ export function lowerDynDispatchMethodCall(lowerer, call, access, recv, arrayRec
5972
6333
  }
5973
6334
  }
5974
6335
  }
5975
- const args = call.arguments.map((arg, i) => i === 0 && predicate ? lowerer.coerceInto(arg, predicate, DYN) : lowerer.lowerExprExpecting(arg, DYN));
6336
+ const args = call.arguments.map((arg, i) => {
6337
+ if (i === 0 && predicate)
6338
+ return lowerer.coerceInto(arg, predicate, DYN);
6339
+ const undefinedArg = lowerStaticallyUndefinedArgument(lowerer, arg);
6340
+ return undefinedArg ? defaultAfterUndefined(undefinedArg, dynUndefinedExpr(locOf(arg))) : lowerer.lowerExprExpecting(arg, DYN);
6341
+ });
5976
6342
  return {
5977
6343
  kind: "dynInvoke",
5978
6344
  recv,
@@ -6098,13 +6464,13 @@ function lowerCaughtPredicateCall(lowerer, call, caughtLocal) {
6098
6464
  * and String(n) lower to (Number::toString with radix 10 IS that
6099
6465
  * conversion, per spec) — booleans the "true"/"false" texts, and strings
6100
6466
  * the identity read (String.prototype.toString returns `this`). The
6101
- * explicit-radix number form keeps its island lowering (ISLAND_SURFACE);
6467
+ * explicit-radix number form uses the native radix formatter;
6102
6468
  * null for other receivers, argument shapes, or non-lib members (a
6103
6469
  * user's own `.toString` takes the ordinary paths). */
6104
6470
  function lowerNumberToStringCall(lowerer, call, access) {
6105
6471
  if (lowerer.chainBlocked(call, access))
6106
6472
  return null;
6107
- if (access.name.text !== "toString" || call.arguments.length !== 0)
6473
+ if (access.name.text !== "toString" || call.arguments.length > 1 || call.arguments.some(ts.isSpreadElement))
6108
6474
  return null;
6109
6475
  const recvKind = lowerer.mapTypeOf(lowerer.typeOf(access.expression))?.kind;
6110
6476
  if (recvKind !== "f64" && recvKind !== "bool" && recvKind !== "string")
@@ -6112,6 +6478,22 @@ function lowerNumberToStringCall(lowerer, call, access) {
6112
6478
  if (!lowerer.isStdlibMember(access))
6113
6479
  return null;
6114
6480
  const operand = lowerer.lowerExpr(access.expression);
6481
+ // JavaScript array and typed-array reads can still be undefined even
6482
+ // when the checker declares a number. Preserve that runtime value and
6483
+ // let native method dispatch format numbers or throw for missing data.
6484
+ if (operand.type.kind === "dyn") {
6485
+ return {
6486
+ kind: "libCall", fn: "dyn.toString", args: [operand,
6487
+ call.arguments[0] ? lowerer.lowerExprExpecting(call.arguments[0], DYN) : dynUndefinedExpr(locOf(call)),
6488
+ { kind: "strLit", value: access.getText(), type: STRING, loc: locOf(call) },
6489
+ ], type: STRING, loc: locOf(call),
6490
+ };
6491
+ }
6492
+ if (call.arguments.length === 1) {
6493
+ if (operand.type.kind !== "f64")
6494
+ return null;
6495
+ return { kind: "libCall", fn: "num.toStringRadix", args: [operand, lowerer.lowerExprExpecting(call.arguments[0], DYN)], type: STRING, loc: locOf(call) };
6496
+ }
6115
6497
  if (operand.type.kind === "string")
6116
6498
  return operand; // identity, receiver evaluated
6117
6499
  if (operand.type.kind !== "f64" && operand.type.kind !== "bool")
@@ -6305,6 +6687,15 @@ function lowerPrimitiveProtoCall(lowerer, call, recv, name, memberSym) {
6305
6687
  if (!lowerer.isStdlibSymbol(memberSym))
6306
6688
  return null;
6307
6689
  const recvKind = lowerer.mapTypeOf(lowerer.typeOf(recv))?.kind;
6690
+ if ((name === "toFixed" || name === "toExponential") && call.arguments.length <= 1 &&
6691
+ !call.arguments.some(ts.isSpreadElement) && isJsSourceFile(call.getSourceFile())) {
6692
+ const operand = lowerer.lowerExpr(recv);
6693
+ if (operand.type.kind === "dyn" || operand.type.kind === "union" && lowerer.dynConvertible(operand.type))
6694
+ return {
6695
+ kind: "dynInvoke", recv: lowerer.coerceToExpected(operand, DYN), method: name, calleeName: `${recv.getText()}.${name}`,
6696
+ args: call.arguments.map((argument) => lowerer.lowerExprExpecting(argument, DYN)), type: DYN, loc: locOf(call),
6697
+ };
6698
+ }
6308
6699
  if (recvKind !== "f64" && recvKind !== "bool" && recvKind !== "string")
6309
6700
  return null;
6310
6701
  const loc = locOf(call);
@@ -6574,15 +6965,14 @@ function templateEscapesValid(raw) {
6574
6965
  * maps to string[] (type-mapper.ts), so the array rides the ordinary
6575
6966
  * slot-directed coercion into whatever the tag's first parameter wants
6576
6967
  * — string[] exactly, an `any` slot through the dyn boundary, a rest
6577
- * pack's first element. `.raw` does not exist on the lowered object:
6578
- * reads fence per member, and String.raw itself lowered above (the raw
6579
- * spans splice directly, no array materializes).
6968
+ * pack's first element. Checked tags receive frozen cooked and raw
6969
+ * arrays with the standard nonenumerable `.raw` descriptor. Typed direct
6970
+ * tags retain the string-array representation.
6580
6971
  *
6581
6972
  * Tag forms: a top-level declared function (the direct-call fast path —
6582
6973
  * overload sets reconcile through the resolved signature exactly like
6583
6974
  * plain calls), an island value under --dynamic (engine method/function
6584
- * call: the engine side sees a plain marshaled array — a tag reading
6585
- * `.raw` there answers undefined where Node carries the raw spans), and
6975
+ * call with the engine's cooked/raw template object), and
6586
6976
  * a checked-dynamic value (the dynCall boundary — a non-function tag
6587
6977
  * throws Node's catchable TypeError). Everything else — generic tags,
6588
6978
  * method tags, function-value bindings — fences by name. */
@@ -6642,10 +7032,11 @@ export function lowerTaggedTemplate(lowerer, expr) {
6642
7032
  if (ts.isIdentifier(expr.tag) && !lowerer.isSelfReference(expr.tag)) {
6643
7033
  if (lowerer.isTopLevelFnSymbol(expr.tag) && !lowerer.peekLocal(expr.tag)) {
6644
7034
  fenceEarlyAliasUse(lowerer, expr.tag, expr);
6645
- if (lowerer.genericFnOf(expr.tag)) {
7035
+ const genericTag = lowerer.genericFnOf(expr.tag);
7036
+ if (genericTag && !genericTag.implicitParams) {
6646
7037
  lowerer.unsupported("SC1090", expr, "tagged templates with generic tag functions");
6647
7038
  }
6648
- const sig = lowerer.fnSigOf(expr.tag);
7039
+ const sig = genericTag ? null : lowerer.fnSigOf(expr.tag);
6649
7040
  if (sig) {
6650
7041
  lowerer.noteEdge(sig.name);
6651
7042
  const args = completeArgs(lowerer, values, sig.params, loc, expr, [strings()]);
@@ -6672,10 +7063,13 @@ export function lowerTaggedTemplate(lowerer, expr) {
6672
7063
  // Checked-dynamic tags (`var f: any; f\`abc\``, dyn property chains):
6673
7064
  // the dynCall boundary — arguments convert into dyn, a non-function
6674
7065
  // tag throws Node's catchable "<name> is not a function" TypeError.
6675
- const callee = lowerer.lowerExpr(expr.tag);
7066
+ let callee = lowerer.lowerExpr(expr.tag);
7067
+ if (callee.type.kind === "func" && isJsSourceFile(expr.getSourceFile()) && lowerer.dynConvertible(callee.type)) {
7068
+ callee = { kind: "dynFrom", value: callee, type: DYN, loc };
7069
+ }
6676
7070
  if (callee.type.kind === "dyn") {
6677
7071
  const args = [
6678
- lowerer.coerceInto(expr.template, strings(), DYN),
7072
+ loweredTemplateStrings(lowerer, expr, pieces.map((piece) => piece.text), loc, pieces.map(templateRawTextOf)),
6679
7073
  ...values.map((a) => lowerer.lowerExprExpecting(a, DYN)),
6680
7074
  ];
6681
7075
  const calleeName = ts.isPropertyAccessExpression(expr.tag) || ts.isElementAccessExpression(expr.tag)
@@ -6687,12 +7081,15 @@ export function lowerTaggedTemplate(lowerer, expr) {
6687
7081
  }
6688
7082
  lowerer.unsupported("SC1090", expr, "tagged templates with this tag form (top-level functions and dynamic values tag; call the function directly otherwise)");
6689
7083
  }
6690
- function loweredTemplateStrings(lowerer, expr, cooked, loc) {
7084
+ function loweredTemplateStrings(lowerer, expr, cooked, loc, raw) {
6691
7085
  // Normal runtime construction keeps this array aligned with the current
6692
7086
  // ScrArr layout in the backend. The old static-header IR node encoded the
6693
7087
  // pre-sparse layout in LLVM and crashed as soon as a tag read its strings.
6694
- const type = arrayOf(STRING);
6695
- const key = `templateStringsGlobal:${loc.file}:${expr.template.getStart()}`;
7088
+ const type = raw ? DYN : arrayOf(STRING);
7089
+ const array = (values) => ({ kind: "dynArrLit", elems: values.map((value) => ({ kind: "dynFrom", value: { kind: "strLit", value, type: STRING, loc }, type: DYN, loc })), type: DYN, loc });
7090
+ const freeze = (value) => ({ kind: "libCall", fn: "dyn.freeze", args: [value], type: DYN, loc });
7091
+ const checked = raw ? freeze({ kind: "libCall", fn: "dyn.defineProperty", args: [array(cooked), { kind: "dynFrom", value: { kind: "strLit", value: "raw", type: STRING, loc }, type: DYN, loc }, { kind: "dynObjLit", fields: [{ key: { kind: "strLit", value: "value", type: STRING, loc }, value: freeze(array(raw)) }], type: DYN, loc }], type: DYN, loc }) : null;
7092
+ const key = `templateStringsGlobal:${loc.file}:${expr.template.getStart()}:${raw ? "checked" : "typed"}`;
6696
7093
  let getter = lowerer.widthHelpers.get(key);
6697
7094
  if (!getter) {
6698
7095
  const site = lowerer.globalsList.length;
@@ -6714,7 +7111,7 @@ function loweredTemplateStrings(lowerer, expr, cooked, loc) {
6714
7111
  {
6715
7112
  kind: "assign",
6716
7113
  localId: globalId,
6717
- value: {
7114
+ value: checked ?? {
6718
7115
  kind: "arrayLit",
6719
7116
  elems: cooked.map((value) => ({ kind: "strLit", value, type: STRING, loc })),
6720
7117
  type,
@@ -6779,6 +7176,17 @@ export function lowerNestedFunctionDecl(lowerer, stmt) {
6779
7176
  throw new InternalCompilerError("lowerer bug: nested function declaration has no active statement list");
6780
7177
  }
6781
7178
  const init = lowerer.lowerLambda(stmt);
7179
+ // Body inference may settle a JS return differently from the initial
7180
+ // checker signature. Publish that same ABI on the hoisted binding and
7181
+ // every mutable capture of it before callers are lowered.
7182
+ if (init.type.kind === "func" && !typeEquals(local.type, init.type)) {
7183
+ local.type = init.type;
7184
+ for (const fn of lowerer.liftedFns)
7185
+ for (const capture of fn.captures ?? []) {
7186
+ if (capture.localId === local.id)
7187
+ capture.type = init.type;
7188
+ }
7189
+ }
6782
7190
  return { kind: "assign", localId: local.id, value: init, loc: locOf(stmt) };
6783
7191
  }
6784
7192
  /** Signature checks + param shapes + IR func type for any lambda-like
@@ -6819,6 +7227,23 @@ export function lambdaSignature(lowerer, node) {
6819
7227
  : "generic arrow/function expressions outside a never-reassigned module-scope binding (only `const f = <T>(x: T) => ...` bindings and top-level generic function declarations monomorphize)");
6820
7228
  }
6821
7229
  const shapes = lowerer.paramShapes(node.parameters);
7230
+ // Error-first callbacks captured by native filesystem adapters receive
7231
+ // the selected runtime overload. Ambient contextual inference can pick
7232
+ // the string overload even when options request a Buffer.
7233
+ if ((ts.isArrowFunction(node) || ts.isFunctionExpression(node)) && ts.isCallExpression(node.parent) &&
7234
+ node.parent.arguments.at(-1) === node) {
7235
+ const builtin = ts.isPropertyAccessExpression(node.parent.expression) ? lowerer.builtinMemberOf(node.parent.expression)
7236
+ : ts.isIdentifier(node.parent.expression) ? lowerer.builtinImportOf(node.parent.expression) : null;
7237
+ if (builtin?.module === "fs" && builtin.member !== "rename" && builtinModuleFnOf(lowerer, builtin.module, builtin.member)?.fn === "fs.callbackCall") {
7238
+ for (let index = 0; index < shapes.length; index++) {
7239
+ if (!node.parameters[index]?.type) {
7240
+ shapes[index].type = DYN;
7241
+ if (shapes[index].bodyType)
7242
+ shapes[index].bodyType = DYN;
7243
+ }
7244
+ }
7245
+ }
7246
+ }
6822
7247
  // A concise arrow over an h2-only stream/session call (`() =>
6823
7248
  // req.stream.destroy()`): the call ALWAYS throws on this lowering
6824
7249
  // (stream is undefined — the streamUndefCall precedent), so the body
@@ -6919,14 +7344,28 @@ export function lambdaSignature(lowerer, node) {
6919
7344
  * object-literal shorthand method to a module-level function and yields
6920
7345
  * the `closure` expression creating it. */
6921
7346
  export function lowerLambda(lowerer, node) {
7347
+ const prepared = (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) ? lowerer.preparedClassFactories.get(node) : undefined;
7348
+ if (prepared)
7349
+ return prepared;
6922
7350
  const loc = locOf(node);
6923
- const { shapes, funcType } = lowerer.lambdaSignature(node);
7351
+ const signature = lowerer.lambdaSignature(node);
7352
+ const { shapes } = signature;
7353
+ let { funcType } = signature;
7354
+ // Reflected JS methods receive the caller's actual `this`, which may
7355
+ // be a Proxy or a descriptor-created object rather than the class.
7356
+ // Fluent methods must return that receiver without a class cast.
7357
+ if (ts.isMethodDeclaration(node) && isJsSourceFile(node.getSourceFile()) &&
7358
+ !node.type && !node.asteriskToken && !hasExplicitJsDocReturn(node) && returnsOnlyThis(node)) {
7359
+ funcType = { ...funcType, ret: funcType.ret.kind === "promise" ? { ...funcType.ret, inner: DYN } : DYN };
7360
+ }
6924
7361
  // A lambda IS a value: the completed-ABI rule applies at birth. The
6925
7362
  // contextual (target) type decides — `(x?: number) => void` may flow
6926
7363
  // into a slot annotated `(x: number | undefined) => void` (same ABI
6927
7364
  // signature), anything else is fenced. Nested function declarations and
6928
7365
  // object-literal shorthand methods aren't expressions — always fenced.
6929
- lowerer.requireExactArityValue(node, ts.isArrowFunction(node) || ts.isFunctionExpression(node) ? node : null, shapes, funcType);
7366
+ if (!(ts.isMethodDeclaration(node) && isJsSourceFile(node.getSourceFile()) &&
7367
+ canBoxFuncIntoDyn(funcType, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))))
7368
+ lowerer.requireExactArityValue(node, ts.isArrowFunction(node) || ts.isFunctionExpression(node) ? node : null, shapes, funcType);
6930
7369
  const nameIdent = !ts.isArrowFunction(node) && node.name && ts.isIdentifier(node.name) ? node.name : null;
6931
7370
  const baseName = nameIdent ? nameIdent.text : "";
6932
7371
  const fnName = `%fn${lowerer.lambdaCounter++}${baseName ? `_${baseName}` : ""}`;
@@ -6950,10 +7389,18 @@ export function lowerLambda(lowerer, node) {
6950
7389
  if (isGenerator &&
6951
7390
  (funcType.ret.kind !== "generator" || (funcType.ret.async === true) !== isAsync))
6952
7391
  lowerer.badType(node, lowerer.typeOf(node));
6953
- const bodyReturn = isGenerator
7392
+ let bodyReturn = isGenerator
6954
7393
  ? lowerer.genBodyReturnType(funcType.ret)
6955
7394
  : lowerer.bodyReturnType(isAsync, funcType.ret);
6956
7395
  const fnCtx = newFnCtx(true, selfSymbol, funcType, bodyReturn);
7396
+ const inferredSignature = isJsSourceFile(node.getSourceFile()) && !node.type ? lowerer.checker.getSignatureFromDeclaration(node) : undefined;
7397
+ const returnsConstructor = inferredSignature && producesConstructor(lowerer, lowerer.checker.getReturnTypeOfSignature(inferredSignature));
7398
+ if (isJsSourceFile(node.getSourceFile()) && !node.type && !isAsync && !isGenerator &&
7399
+ (bodyReturn.kind === "classval" || bodyReturn.kind === "date" || bodyReturn.kind === "symbol" || bodyReturn.kind === "record" ||
7400
+ (bodyReturn.kind === "dyn" || bodyReturn.kind === "func") && returnsConstructor)) {
7401
+ fnCtx.inferReturn = { entries: [] };
7402
+ }
7403
+ fnCtx.inheritsArguments = ts.isArrowFunction(node);
6957
7404
  fnCtx.isAsync = isAsync;
6958
7405
  if (isGenerator && funcType.ret.kind === "generator") {
6959
7406
  fnCtx.generator = generatorMeta(lowerer, funcType.ret);
@@ -6967,7 +7414,7 @@ export function lowerLambda(lowerer, node) {
6967
7414
  // and a method nested inside another method never captures its owner.
6968
7415
  if (isJsSourceFile(node.getSourceFile()) && !ts.isArrowFunction(node)) {
6969
7416
  const receiver = lowerer.declareThis(DYN);
6970
- prologue.unshift({ kind: "varDecl", localId: receiver.id, init: { kind: "libCall", fn: "dyn.this", args: [], type: DYN, loc }, loc });
7417
+ prologue.unshift({ kind: "varDecl", localId: receiver.id, init: { kind: "libCall", fn: isGenerator ? "dyn.generatorThis" : "dyn.this", args: [], type: DYN, loc }, loc });
6971
7418
  }
6972
7419
  // The synthetic trailing dyn-array param carries `arguments`.
6973
7420
  // Parameterized functions receive all actual arguments; zero-param
@@ -6977,6 +7424,15 @@ export function lowerLambda(lowerer, node) {
6977
7424
  params.push({ localId: argsLocal.id, name: "%arguments", type: DYN });
6978
7425
  fnCtx.argumentsLocal = argsLocal;
6979
7426
  }
7427
+ if (isJsSourceFile(node.getSourceFile()) && !ts.isArrowFunction(node) &&
7428
+ shapes.length === 1 && shapes[0]?.mode === "dynRest" && bodyReadsArguments(node)) {
7429
+ const argsLocal = lowerer.declareHiddenLocal("%arguments", DYN);
7430
+ prologue.push({ kind: "varDecl", localId: argsLocal.id, init: {
7431
+ kind: "dynInvoke", recv: varRef(params[0].localId, DYN, loc), method: "slice",
7432
+ calleeName: "Array.prototype.slice", args: [], type: DYN, loc,
7433
+ }, loc });
7434
+ fnCtx.argumentsLocal = argsLocal;
7435
+ }
6980
7436
  let body;
6981
7437
  if (ts.isBlock(node.body)) {
6982
7438
  body = lowerer.lowerStmts(node.body.statements);
@@ -7011,7 +7467,7 @@ export function lowerLambda(lowerer, node) {
7011
7467
  else {
7012
7468
  // Concise and block bodies use the same destination layout for
7013
7469
  // fresh literals. Async bodies must inspect promises first.
7014
- let value = isAsync ? lowerer.lowerExpr(bodyExpr) : lowerer.lowerExprExpecting(bodyExpr, bodyReturn);
7470
+ let value = isAsync || fnCtx.inferReturn ? lowerer.lowerExpr(bodyExpr) : lowerer.lowerExprExpecting(bodyExpr, bodyReturn);
7015
7471
  // An async concise body whose value is itself a promise
7016
7472
  // (`async () => p`): the async machinery RESOLVES the returned
7017
7473
  // thenable into the function's own promise — lowerReturnValue's
@@ -7025,17 +7481,25 @@ export function lowerLambda(lowerer, node) {
7025
7481
  : [
7026
7482
  {
7027
7483
  kind: "return",
7028
- value: lowerer.coerceInto(bodyExpr, value, bodyReturn),
7484
+ value: fnCtx.inferReturn ? value : lowerer.coerceInto(bodyExpr, value, bodyReturn),
7029
7485
  loc: locOf(node.body),
7030
7486
  },
7031
7487
  ];
7488
+ if (fnCtx.inferReturn && body[0]?.kind === "return")
7489
+ fnCtx.inferReturn.entries.push({ stmt: body[0], node: bodyExpr });
7032
7490
  }
7033
7491
  }
7492
+ if (fnCtx.inferReturn) {
7493
+ bodyReturn = resolveInferredReturn(lowerer, { returnType: bodyReturn }, fnCtx.inferReturn, body, node);
7494
+ funcType = { ...funcType, ret: bodyReturn };
7495
+ fnCtx.returnType = bodyReturn;
7496
+ }
7034
7497
  body = [...prologue, ...body];
7035
7498
  // Bare-expression bodies never pass through lowerStmts, so the
7036
7499
  // lib-boundary chokepoint runs here (idempotent for block bodies,
7037
7500
  // whose statements were already walked). A fence poisons the
7038
7501
  // enclosing statement — the lambda IS part of it.
7502
+ body = lowerSurplusCalls(lowerer, body);
7039
7503
  enforceLibBoundary(lowerer, body);
7040
7504
  appendImplicitUndefinedReturn(lowerer, body, bodyReturn, loc);
7041
7505
  const ctx = lowerer.ctx;
@@ -7189,7 +7653,7 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
7189
7653
  const member = access.name.text;
7190
7654
  if (member !== "then" && member !== "catch" && member !== "finally")
7191
7655
  return null;
7192
- let recvT = lowerer.mapTypeOf(lowerer.typeOf(access.expression));
7656
+ let recvT = lowerer.mapTypeOf(lowerer.typeOf(access.expression)) ?? dynFallbackType(lowerer, access.expression, lowerer.typeOf(access.expression));
7193
7657
  // A dynamic-import promise under an unmappable checker type
7194
7658
  // (`Promise<typeof import("./m")>` — module-namespace types have no
7195
7659
  // static mapping): the BINDING holds the island promise
@@ -7242,6 +7706,8 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
7242
7706
  loc,
7243
7707
  };
7244
7708
  }
7709
+ if (receiver.type.kind === "dyn" && lowerer.dynConvertible(recvT))
7710
+ receiver = lowerer.coerceInto(access.expression, receiver, recvT);
7245
7711
  if (receiver.type.kind !== "promise") {
7246
7712
  // mapTypeOf said promise but the value lowered as something else —
7247
7713
  // a lowering gap, named rather than ICEd on.
@@ -7501,7 +7967,7 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
7501
7967
  value: {
7502
7968
  kind: "dynCall",
7503
7969
  callee: { kind: "varRef", localId: cbLocal.id, type: DYN, loc },
7504
- calleeName: jsFuncNameOf(call.arguments[0]) ?? "onFulfilled",
7970
+ calleeName: jsFuncNameOf(call.arguments[0], lowerer) ?? "onFulfilled",
7505
7971
  args: handlerArgs,
7506
7972
  type: DYN,
7507
7973
  loc,
@@ -7534,7 +8000,8 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
7534
8000
  lowerer.unsupported("SC1090", call.arguments[0], "then handlers with more than one parameter (the two-argument onRejected form has no lowering — chain .catch(...) instead)");
7535
8001
  }
7536
8002
  const param = cb.type.params[0];
7537
- if (param !== undefined && !typeEquals(param, inner)) {
8003
+ if (param !== undefined && !typeEquals(param, inner) &&
8004
+ !(param.kind === "dyn" && (inner.kind === "void" || lowerer.dynConvertible(inner)))) {
7538
8005
  lowerer.unsupported("SC1090", call.arguments[0], `then handlers whose parameter is not the settled value's type (expected '${lowerer.fmt(inner)}', got '${lowerer.fmt(param)}')`);
7539
8006
  }
7540
8007
  const resultT = lowerer.mapTypeOf(lowerer.typeOf(call));
@@ -7564,10 +8031,12 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
7564
8031
  if (param !== undefined && inner.kind !== "void") {
7565
8032
  const vLocal = lowerer.declareHiddenLocal("v", inner);
7566
8033
  body.push({ kind: "varDecl", localId: vLocal.id, init: awaitE, loc });
7567
- handlerArgs = [{ kind: "varRef", localId: vLocal.id, type: inner, loc }];
8034
+ handlerArgs = [lowerer.coerceToExpected({ kind: "varRef", localId: vLocal.id, type: inner, loc }, param)];
7568
8035
  }
7569
8036
  else {
7570
8037
  body.push({ kind: "exprStmt", expr: awaitE, loc });
8038
+ if (param !== undefined)
8039
+ handlerArgs = [dynUndefinedExpr(loc)];
7571
8040
  }
7572
8041
  const handlerCall = {
7573
8042
  kind: "callValue",
@@ -7623,6 +8092,14 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
7623
8092
  }
7624
8093
  if (member === "finally") {
7625
8094
  const cb = lowerer.lowerExpr(call.arguments[0]);
8095
+ if (lowerer.dynConvertible(promT) && lowerer.dynConvertible(cb.type)) {
8096
+ const result = {
8097
+ kind: "dynInvoke", recv: lowerer.coerceToExpected(receiver, DYN),
8098
+ method: "finally", calleeName: access.getText(),
8099
+ args: [lowerer.coerceToExpected(cb, DYN)], type: DYN, loc,
8100
+ };
8101
+ return lowerer.coerceToExpected(result, promT);
8102
+ }
7626
8103
  if (cb.type.kind !== "func" || cb.type.params.length !== 0 || cb.type.ret.kind !== "void") {
7627
8104
  lowerer.unsupported("SC1090", call.arguments[0], "finally callbacks with parameters or a return value (use () => { ... })");
7628
8105
  }
@@ -7699,7 +8176,8 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
7699
8176
  // receiver, passes fulfillments through as dyn, and on rejection
7700
8177
  // calls the boxed handler with caughtToDyn's identity-preserving
7701
8178
  // snapshot (the dyn-then desugar's catch twin).
7702
- if (member === "catch" && inner.kind === "dyn") {
8179
+ if (member === "catch" && (inner.kind === "dyn" || isJsSourceFile(call.getSourceFile()) &&
8180
+ (inner.kind === "void" || lowerer.dynConvertible(inner)))) {
7703
8181
  let cb = lowerer.lowerExpr(call.arguments[0]);
7704
8182
  if (cb.type.kind === "func" &&
7705
8183
  canBoxFuncIntoDyn(cb.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
@@ -7716,20 +8194,11 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
7716
8194
  const pLocal = lowerer.declareHiddenLocal("p", promT);
7717
8195
  const cbLocal = lowerer.declareHiddenLocal("cb", DYN);
7718
8196
  const eLocal = lowerer.declareHiddenLocal("e", CAUGHT);
7719
- const vLocal = lowerer.declareHiddenLocal("v", DYN);
8197
+ const vLocal = inner.kind === "void" ? null : lowerer.declareHiddenLocal("v", inner);
8198
+ const awaited = { kind: "awaitExpr", value: { kind: "varRef", localId: pLocal.id, type: promT, loc }, type: inner, loc };
7720
8199
  const tryBody = [
7721
- {
7722
- kind: "varDecl",
7723
- localId: vLocal.id,
7724
- init: {
7725
- kind: "awaitExpr",
7726
- value: { kind: "varRef", localId: pLocal.id, type: promT, loc },
7727
- type: DYN,
7728
- loc,
7729
- },
7730
- loc,
7731
- },
7732
- { kind: "return", value: { kind: "varRef", localId: vLocal.id, type: DYN, loc }, loc },
8200
+ vLocal ? { kind: "varDecl", localId: vLocal.id, init: awaited, loc } : { kind: "exprStmt", expr: awaited, loc },
8201
+ { kind: "return", value: vLocal ? lowerer.coerceToExpected(varRef(vLocal.id, inner, loc), DYN) : dynUndefinedExpr(loc), loc },
7733
8202
  ];
7734
8203
  const catchBody = [
7735
8204
  {
@@ -7737,7 +8206,7 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
7737
8206
  value: {
7738
8207
  kind: "dynCall",
7739
8208
  callee: { kind: "varRef", localId: cbLocal.id, type: DYN, loc },
7740
- calleeName: jsFuncNameOf(call.arguments[0]) ?? "onRejected",
8209
+ calleeName: jsFuncNameOf(call.arguments[0], lowerer) ?? "onRejected",
7741
8210
  args: [
7742
8211
  {
7743
8212
  kind: "caughtToDyn",
@@ -8540,14 +9009,23 @@ function lowerObjectStaticCall(lowerer, call, access) {
8540
9009
  !call.arguments.some(ts.isSpreadElement) && !lowerer.dynamic) {
8541
9010
  let object = lowerer.lowerExpr(call.arguments[0]);
8542
9011
  if (object.type.kind === "func") {
8543
- const fnName = jsFuncNameOf(call.arguments[0]);
9012
+ const fnName = jsFuncNameOf(call.arguments[0], lowerer);
8544
9013
  object = { kind: "dynFrom", value: object, type: DYN, loc: locOf(call),
8545
9014
  ...(fnName !== null ? { fnName } : {}) };
8546
9015
  }
9016
+ if (object.type.kind !== "dyn" && canConvertToDyn(object.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id)))
9017
+ object = lowerer.coerceInto(call.arguments[0], object, DYN);
8547
9018
  if (object.type.kind === "dyn") {
8548
9019
  const loc = locOf(call);
8549
- if (member === "getPrototypeOf")
8550
- return { kind: "libCall", fn: "dyn.getPrototype", args: [object], type: DYN, loc };
9020
+ if (member === "getPrototypeOf") {
9021
+ let parent = call.parent;
9022
+ while (parent && ts.isParenthesizedExpression(parent))
9023
+ parent = parent.parent;
9024
+ const identityOnly = !!parent && ts.isBinaryExpression(parent) &&
9025
+ [ts.SyntaxKind.EqualsEqualsEqualsToken, ts.SyntaxKind.ExclamationEqualsEqualsToken].includes(parent.operatorToken.kind);
9026
+ return { kind: "libCall", fn: "dyn.getPrototype", args: [object], type: DYN, loc,
9027
+ ...(identityOnly ? { prototypeIdentityOnly: true } : {}) };
9028
+ }
8551
9029
  const prototype = lowerer.lowerExprExpecting(call.arguments[1], DYN);
8552
9030
  if (prototype.type.kind === "dyn")
8553
9031
  return { kind: "libCall", fn: "dyn.setPrototype", args: [object, prototype], type: DYN, loc };
@@ -8600,7 +9078,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
8600
9078
  if (unitTest)
8601
9079
  return unitTest;
8602
9080
  if (lk === "dyn" || rk === "dyn" || lk === "jsval" || rk === "jsval") {
8603
- lowerer.noLowering("Object.is over a dynamic operand", call, "validate/narrow the value first (strict equality's rule) — SameValue only differs from === on numbers (NaN, ±0)");
9081
+ return { kind: "libCall", fn: "dyn.sameValue", args: [lowerer.coerceInto(leftNode, left, DYN), lowerer.coerceInto(rightNode, right, DYN)], type: BOOL, loc };
8604
9082
  }
8605
9083
  if (left.type.kind === "union" || right.type.kind === "union") {
8606
9084
  const ut = left.type.kind === "union" ? left.type : right.type;
@@ -8728,7 +9206,8 @@ function lowerObjectStaticCall(lowerer, call, access) {
8728
9206
  return prototype;
8729
9207
  if (isJsSourceFile(call.getSourceFile()) && call.arguments.length > 0 && !call.arguments.some(ts.isSpreadElement)) {
8730
9208
  const target = tryLowerExpression(lowerer, call.arguments[0]);
8731
- if (target?.type.kind === "func" && lowerer.dynConvertible(target.type)) {
9209
+ if (target && ((target.type.kind === "func" && lowerer.dynConvertible(target.type)) ||
9210
+ (target.type.kind === "object" && lowerer.dynConvertible(target.type)))) {
8732
9211
  const loc = locOf(call);
8733
9212
  return { kind: "libCall", fn: "dyn.assignAll", args: [lowerer.coerceToExpected(target, DYN),
8734
9213
  { kind: "dynArrLit", elems: call.arguments.slice(1).map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc },
@@ -8904,6 +9383,14 @@ function lowerObjectStaticCall(lowerer, call, access) {
8904
9383
  if (call.arguments.some((a) => ts.isSpreadElement(a)))
8905
9384
  return null;
8906
9385
  let target = tryLowerExpression(lowerer, call.arguments[0]);
9386
+ const targetNode = call.arguments[0];
9387
+ // The checker gives C.prototype the instance type, but its lowered
9388
+ // value is the shared prototype table, not an instance to unbox.
9389
+ const prototypeTarget = ts.isPropertyAccessExpression(targetNode) && targetNode.name.text === "prototype" &&
9390
+ (exactClassOfReceiver(lowerer, targetNode.expression) !== null || storedClassValueType(lowerer, targetNode.expression)?.kind === "classval");
9391
+ const declaredTarget = target?.type.kind === "dyn" && !prototypeTarget && !isJsSourceFile(targetNode.getSourceFile()) ? lowerer.mapTypeOf(lowerer.typeOf(targetNode)) : null;
9392
+ if (target && declaredTarget && isDynTypedRefType(declaredTarget))
9393
+ target = lowerer.coerceToExpected(target, declaredTarget);
8907
9394
  if (target && member === "defineProperty") {
8908
9395
  const native = lowerClassDataDescriptor(lowerer, call, member, target);
8909
9396
  if (native)
@@ -8915,15 +9402,14 @@ function lowerObjectStaticCall(lowerer, call, access) {
8915
9402
  return descriptor;
8916
9403
  target = lowerer.coerceToExpected(target, DYN);
8917
9404
  }
8918
- // Error.cause owns a live data-property slot shared with its checked
8919
- // view. Other native fields do not yet synchronize descriptor edits.
9405
+ // Error instances share a live property table with their checked view.
8920
9406
  const keyNode = call.arguments[1];
8921
9407
  if (target?.type.kind === "object" && target.type.className !== "%DOMException" && lowerer.errorHierarchyClassOf(target.type.className) &&
8922
- ts.isStringLiteral(keyNode) && keyNode.text === "cause") {
9408
+ ((ts.isStringLiteral(keyNode) && (keyNode.text === "cause" || keyNode.text === "message")) || lowerer.mapTypeOf(lowerer.typeOf(keyNode))?.kind === "symbol")) {
8923
9409
  target = lowerer.coerceToExpected(target, DYN);
8924
9410
  }
8925
9411
  if (target?.type.kind === "func" && lowerer.dynConvertible(target.type)) {
8926
- const fnName = jsFuncNameOf(call.arguments[0]);
9412
+ const fnName = jsFuncNameOf(call.arguments[0], lowerer);
8927
9413
  target = { kind: "dynFrom", value: target, type: DYN, loc: locOf(call.arguments[0]), ...(fnName !== null ? { fnName } : {}) };
8928
9414
  }
8929
9415
  const descriptorPrimitive = member === "getOwnPropertyDescriptor" && target &&
@@ -8952,6 +9438,9 @@ function lowerObjectStaticCall(lowerer, call, access) {
8952
9438
  // static shapes have no property table to extend.
8953
9439
  if (member === "defineProperties" && call.arguments.length === 2 &&
8954
9440
  !call.arguments.some((a) => ts.isSpreadElement(a))) {
9441
+ const prototype = lowerClassPrototypeDescriptors(lowerer, call, member);
9442
+ if (prototype)
9443
+ return prototype;
8955
9444
  let target = tryLowerExpression(lowerer, call.arguments[0]);
8956
9445
  if (target) {
8957
9446
  const native = lowerClassDataDescriptor(lowerer, call, member, target);
@@ -8964,7 +9453,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
8964
9453
  // wrapper returned later reads the same table.
8965
9454
  if (target && target.type.kind === "func" &&
8966
9455
  canBoxFuncIntoDyn(target.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
8967
- const fnName = jsFuncNameOf(call.arguments[0]);
9456
+ const fnName = jsFuncNameOf(call.arguments[0], lowerer);
8968
9457
  target = { kind: "dynFrom", value: target, type: DYN, loc: locOf(call.arguments[0]), ...(fnName !== null ? { fnName } : {}) };
8969
9458
  }
8970
9459
  if (target && isUnitType(target.type)) {
@@ -9019,7 +9508,8 @@ function lowerObjectStaticCall(lowerer, call, access) {
9019
9508
  let inner = argNode;
9020
9509
  while (ts.isParenthesizedExpression(inner) || ts.isAsExpression(inner))
9021
9510
  inner = inner.expression;
9022
- const value = lowerer.lowerExpr(argNode);
9511
+ const value = isJsSourceFile(call.getSourceFile()) && (ts.isObjectLiteralExpression(inner) || ts.isArrayLiteralExpression(inner))
9512
+ ? lowerer.lowerExprExpecting(argNode, DYN) : lowerer.lowerExpr(argNode);
9023
9513
  if (value.type.kind === "dyn")
9024
9514
  return { kind: "libCall", fn: "dyn.freeze", args: [value], type: DYN, loc: locOf(call) };
9025
9515
  if (ts.isObjectLiteralExpression(inner) || ts.isArrayLiteralExpression(inner)) {
@@ -9048,14 +9538,19 @@ function lowerObjectStaticCall(lowerer, call, access) {
9048
9538
  const recvNode = call.arguments[0];
9049
9539
  const keyNode = call.arguments[1];
9050
9540
  const probed = tryLowerExpression(lowerer, recvNode);
9541
+ const constructor = probed?.type.kind === "classval" ? lowerer.classes.get(probed.type.className) : undefined;
9051
9542
  // A CHECKED-DYNAMIC receiver (the JS file-scope object-literal
9052
9543
  // identity story): the runtime dyn probe — OBJ member presence, ARR
9053
9544
  // index bounds, Node's ToObject TypeError on nullish.
9054
- if (probed?.type.kind === "dyn" || (probed && isDynTypedRefType(probed.type)) || (probed?.type.kind === "func" && lowerer.dynConvertible(probed.type))) {
9545
+ if (probed?.type.kind === "dyn" || (probed && isDynTypedRefType(probed.type)) ||
9546
+ (probed?.type.kind === "object" && lowerer.errorHierarchyClassOf(probed.type.className)) ||
9547
+ (probed && constructor && (constructor.callableBase || hasRuntimeStatics(constructor))) ||
9548
+ (probed?.type.kind === "func" && lowerer.dynConvertible(probed.type))) {
9055
9549
  const loc = locOf(call);
9056
9550
  const receiver = lowerer.coerceToExpected(probed, DYN);
9057
9551
  const rawKey = lowerer.lowerExpr(keyNode);
9058
- if (rawKey.type.kind === "dyn" || rawKey.type.kind === "symbol")
9552
+ if (rawKey.type.kind === "dyn" || rawKey.type.kind === "symbol" ||
9553
+ rawKey.type.kind === "union" && lowerer.dynConvertible(rawKey.type))
9059
9554
  return {
9060
9555
  kind: "libCall", fn: "dyn.hasOwnComputed", args: [receiver, lowerer.coerceToExpected(rawKey, DYN)], type: BOOL, loc,
9061
9556
  };
@@ -9140,7 +9635,8 @@ function lowerObjectStaticCall(lowerer, call, access) {
9140
9635
  const isPrimitive = probed !== null && probed !== undefined &&
9141
9636
  (isUnitType(probed.type) || probed.type.kind === "string" ||
9142
9637
  probed.type.kind === "f64" || probed.type.kind === "bool");
9143
- if (isDyn || isPrimitive || isFunction || (probed && isDynTypedRefType(probed.type))) {
9638
+ const isJsUnion = probed?.type.kind === "union" && isJsSourceFile(call.getSourceFile()) && lowerer.dynConvertible(probed.type);
9639
+ if (isDyn || isPrimitive || isFunction || isJsUnion || (probed && isDynTypedRefType(probed.type))) {
9144
9640
  const fn = member === "keys" ? "dyn.objKeys" : member === "values" ? "dyn.objValues" : "dyn.objEntries";
9145
9641
  let v = lowerer.lowerExpr(argNode);
9146
9642
  if (v.type.kind !== "dyn")
@@ -9149,14 +9645,11 @@ function lowerObjectStaticCall(lowerer, call, access) {
9149
9645
  }
9150
9646
  }
9151
9647
  let argIr = lowerer.mapTypeOf(lowerer.typeOf(argNode));
9152
- // JS: an unmappable CHECKER type over a value that lowered to a real
9153
- // record (the narrowed export-table literal) — the lowered value's
9154
- // shape is the honest dispatch key, exactly the identity-Set stance.
9155
- if (argIr === null && isJsSourceFile(argNode.getSourceFile())) {
9156
- const probed = tryLowerExpression(lowerer, argNode);
9157
- if (probed?.type.kind === "record")
9158
- argIr = probed.type;
9159
- }
9648
+ // Inferred records can carry runtime-optional index values that the
9649
+ // checker omits (named regex captures). Enumerate the represented shape.
9650
+ const represented = tryLowerExpression(lowerer, argNode);
9651
+ if (represented?.type.kind === "record")
9652
+ argIr = represented.type;
9160
9653
  if (argIr?.kind !== "record")
9161
9654
  return null; // Maps, classes, arrays → the SC2020 fence
9162
9655
  const shape = lowerer.shapes.get(argIr.shapeId);
@@ -9221,7 +9714,6 @@ function lowerObjectStaticCall(lowerer, call, access) {
9221
9714
  const recT = argIr;
9222
9715
  const ref = { kind: "varRef", localId: "r.0", type: recT, loc };
9223
9716
  const outRef = { kind: "varRef", localId: "out.0", type: resultT, loc };
9224
- lowerer.arrHofHelpers.set(key, helper);
9225
9717
  const fn = {
9226
9718
  name: helper,
9227
9719
  params: [{ localId: "r.0", name: "r", type: recT }],
@@ -9250,6 +9742,8 @@ function lowerObjectStaticCall(lowerer, call, access) {
9250
9742
  return null;
9251
9743
  if (typeEquals(vt, valueT))
9252
9744
  return value;
9745
+ if (valueT.kind === "dyn" && lowerer.dynConvertible(vt))
9746
+ return lowerer.coerceToExpected(value, DYN);
9253
9747
  if (valueT.kind === "union" && vt.kind !== "union") {
9254
9748
  const tag = lowerer.armTag(valueT.unionId, vt);
9255
9749
  if (tag >= 0) {
@@ -9269,7 +9763,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
9269
9763
  guardUndefTag = undefTag;
9270
9764
  const arms = lowerer.unions.get(f.type.unionId)?.arms ?? [];
9271
9765
  const others = arms.filter((a) => a.kind !== "undefinedT");
9272
- if (typeEquals(f.type, valueT ?? f.type)) {
9766
+ if (valueT?.kind === "dyn" || typeEquals(f.type, valueT ?? f.type)) {
9273
9767
  // The field union IS the result union (single-field shapes):
9274
9768
  // push the raw box — but then the undefined skip must NOT
9275
9769
  // narrow. Handled below via vt === valueT.
@@ -9293,7 +9787,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
9293
9787
  "cannot re-tag into the result element type — read the fields directly)");
9294
9788
  }
9295
9789
  }
9296
- else if (!typeEquals(f.type, valueT ?? f.type)) {
9790
+ else if (valueT?.kind !== "dyn" && !typeEquals(f.type, valueT ?? f.type)) {
9297
9791
  lowerer.unsupported("SC1090", call, `Object.${member} over '${lowerer.fmt(argIr)}' (field '${f.name}' is a union that cannot ` +
9298
9792
  "re-tag into the result element type — read the fields directly)");
9299
9793
  }
@@ -9333,6 +9827,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
9333
9827
  fn.body = body;
9334
9828
  };
9335
9829
  finalize();
9830
+ lowerer.arrHofHelpers.set(key, helper);
9336
9831
  lowerer.shapeOrderHelperFinalizers.push(finalize);
9337
9832
  lowerer.liftedFns.push(fn);
9338
9833
  }
@@ -9381,6 +9876,15 @@ export function lowerFunction(lowerer, decl) {
9381
9876
  params.push({ localId: argsLocal.id, name: "%arguments", type: DYN });
9382
9877
  ctx.argumentsLocal = argsLocal;
9383
9878
  }
9879
+ if (isJsSourceFile(decl.getSourceFile()) && sig.params.length === 1 &&
9880
+ sig.params[0]?.mode === "dynRest" && bodyReadsArguments(decl)) {
9881
+ const argsLocal = lowerer.declareHiddenLocal("%arguments", DYN);
9882
+ prologue.push({ kind: "varDecl", localId: argsLocal.id, init: {
9883
+ kind: "dynInvoke", recv: varRef(params[0].localId, DYN, locOf(decl)), method: "slice",
9884
+ calleeName: "Array.prototype.slice", args: [], type: DYN, loc: locOf(decl),
9885
+ }, loc: locOf(decl) });
9886
+ ctx.argumentsLocal = argsLocal;
9887
+ }
9384
9888
  const bodyBlock = blockBodyOf(decl);
9385
9889
  if (!bodyBlock) {
9386
9890
  lowerer.unsupported("SC1090", decl, "function declarations whose block body the frontend cannot locate");
@@ -9537,6 +10041,13 @@ export function lowerRecordFieldCall(lowerer, call, access) {
9537
10041
  return { kind: "callValue", callee, args, type: callee.type.ret, loc: locOf(call) };
9538
10042
  }
9539
10043
  const target = lowerer.fieldTarget(access);
10044
+ const loc = locOf(call);
10045
+ const receiverLocal = target && isJsSourceFile(call.getSourceFile())
10046
+ ? lowerer.declareHiddenLocal("%callReceiver", target.obj.type) : null;
10047
+ const init = target && receiverLocal
10048
+ ? { kind: "varDecl", localId: receiverLocal.id, init: target.obj, loc } : null;
10049
+ if (target && receiverLocal)
10050
+ target.obj = varRef(receiverLocal.id, receiverLocal.type, loc);
9540
10051
  let callee = target ? lowerer.fieldGetExpr(target, locOf(access), access) : null;
9541
10052
  if (!callee)
9542
10053
  return null;
@@ -9545,10 +10056,24 @@ export function lowerRecordFieldCall(lowerer, call, access) {
9545
10056
  // `.bold` (the chalk shape).
9546
10057
  if (callee.type.kind === "record")
9547
10058
  callee = lowerer.hybridCallUnwrap(callee);
10059
+ // Inferred JavaScript option records can retain checked callables in
10060
+ // fields even when the checker only describes those members as any.
10061
+ if (callee.type.kind === "dyn" && isJsSourceFile(call.getSourceFile())) {
10062
+ const receiver = target && receiverLocal ? lowerer.coerceToExpected(target.obj, DYN) : undefined;
10063
+ const spread = call.arguments.some(ts.isSpreadElement) ? lowerSpreadArgsCall(lowerer, call, callee, loc) : null;
10064
+ if (spread && spread.kind !== "dynCall")
10065
+ lowerer.unsupported("SC1090", call, "checked record property call spread arguments");
10066
+ const result = spread ? (receiver ? { ...spread, receiver } : spread) : {
10067
+ kind: "dynCall", callee, ...(receiver ? { receiver } : {}), calleeName: access.getText(),
10068
+ args: call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc,
10069
+ };
10070
+ return init ? { kind: "seqExpr", stmts: [init], result, type: result.type, loc } : result;
10071
+ }
9548
10072
  if (callee.type.kind !== "func")
9549
10073
  lowerer.badType(access, lowerer.typeOf(access));
9550
10074
  const args = completeFuncValueArgs(lowerer, call, callee.type, locOf(call));
9551
- return { kind: "callValue", callee, args, type: callee.type.ret, loc: locOf(call) };
10075
+ const result = { kind: "callValue", callee, ...(target && receiverLocal ? { receiver: lowerer.coerceToExpected(target.obj, DYN) } : {}), args, type: callee.type.ret, loc };
10076
+ return init ? { kind: "seqExpr", stmts: [init], result, type: result.type, loc } : result;
9552
10077
  }
9553
10078
  /** The function-like node behind an object-literal generic-method member:
9554
10079
  * the MethodDeclaration itself (`{ m<T>(x: T) {...} }`) or a generic
@@ -10206,7 +10731,8 @@ export function requireObjLitGenericReceiver(lowerer, blame, recvExpr, literal,
10206
10731
  * direct `call` of the instance with the receiver unevaluated. Claims
10207
10732
  * every call whose member is generic-callable — lowering it or fencing
10208
10733
  * with a named message. */
10209
- /** URL.revokeObjectURL() with NO argument: Node's ERR_MISSING_ARGS
10734
+ /** The URL factories use the constructor's conversion order and parser.
10735
+ * URL.revokeObjectURL() with NO argument: Node's ERR_MISSING_ARGS
10210
10736
  * throws before the registry lookup, so the zero-argument contract is
10211
10737
  * exact without any blob machinery. The one-argument form (Node's
10212
10738
  * silent no-op for unregistered ids) and createObjectURL keep their
@@ -10214,12 +10740,15 @@ export function requireObjLitGenericReceiver(lowerer, blame, recvExpr, literal,
10214
10740
  function lowerUrlStaticCall(lowerer, call, callee) {
10215
10741
  if (!ts.isPropertyAccessExpression(callee) || callee.questionDotToken !== undefined)
10216
10742
  return null;
10217
- if (!ts.isIdentifier(callee.expression) || callee.expression.text !== "URL")
10218
- return null;
10219
- if (callee.name.text !== "revokeObjectURL" || call.arguments.length !== 0)
10743
+ if (!ts.isIdentifier(callee.expression))
10220
10744
  return null;
10221
10745
  const sym = lowerer.resolveValueSymbol(callee.expression);
10222
- if (!sym || !lowerer.isStdlibSymbol(sym))
10746
+ if (!sym || !lowerer.isStdlibSymbol(sym) || sym.name !== "URL")
10747
+ return null;
10748
+ if (callee.name.text === "canParse" || callee.name.text === "parse") {
10749
+ return lowerUrlFactory(lowerer, call, callee.name.text);
10750
+ }
10751
+ if (callee.name.text !== "revokeObjectURL" || call.arguments.length !== 0)
10223
10752
  return null;
10224
10753
  return nodeThrowExpr(1, "ERR_MISSING_ARGS", 'The "url" argument must be specified', VOID, locOf(call));
10225
10754
  }
@@ -10404,6 +10933,14 @@ function lowerObjLitGenericMethodCall(lowerer, call, access) {
10404
10933
  const propSym = lowerer.checker.getPropertyOfType(recvT, name);
10405
10934
  if (!propSym)
10406
10935
  return null;
10936
+ const propertyDecl = lowerer.checker.valueDeclarationOf(propSym);
10937
+ if (propertyDecl && ts.isShorthandPropertyAssignment(propertyDecl) && ts.isIdentifier(propertyDecl.name) && ts.isObjectLiteralExpression(propertyDecl.parent)) {
10938
+ requireObjLitGenericReceiver(lowerer, call, access.expression, propertyDecl.parent, name);
10939
+ const targetSymbol = lowerer.checker.getShorthandAssignmentValueSymbol(propertyDecl);
10940
+ const target = targetSymbol ? lowerer.genericFnsBySymbol.get((targetSymbol.flags & ts.SymbolFlags.Alias ? lowerer.checker.getAliasedSymbol(targetSymbol) : targetSymbol)) : undefined;
10941
+ if (target)
10942
+ return lowerer.lowerGenericCall(call, target);
10943
+ }
10407
10944
  if (!isGenericCallableMemberType(lowerer.checker.getTypeOfSymbol(propSym), lowerer.checker))
10408
10945
  return null;
10409
10946
  // CLASS members belong to the class path (lowerClassGenericMethodCall
@@ -10492,9 +11029,11 @@ export function lowerObjectMethodCall(lowerer, call, access) {
10492
11029
  // type still belongs to the unspecialized body (plane.normal.dot()).
10493
11030
  // Use the lowered receiver's representation and retain its evaluation.
10494
11031
  const probe = mappedReceiver?.kind !== "object" && (lowerer.implicitParamTypes !== null || ts.isNewExpression(access.expression) ||
10495
- isJsSourceFile(call.getSourceFile()) && ts.isCallExpression(access.expression))
10496
- ? tryLowerExpression(lowerer, access.expression) : null;
10497
- const specializedReceiver = probe?.type.kind === "object" ? probe : null;
11032
+ isJsSourceFile(call.getSourceFile()))
11033
+ ? ts.isNewExpression(access.expression) ? lowerer.lowerExpr(access.expression) : tryLowerExpression(lowerer, access.expression)
11034
+ : null;
11035
+ const specializedReceiver = probe?.type.kind === "object" || probe?.type.kind === "union" &&
11036
+ lowerer.unions.get(probe.type.unionId)?.arms.some((arm) => arm.kind === "object") ? probe : null;
10498
11037
  if (specializedReceiver)
10499
11038
  mappedReceiver = specializedReceiver.type;
10500
11039
  if (mappedReceiver?.kind === "union") {
@@ -10502,6 +11041,11 @@ export function lowerObjectMethodCall(lowerer, call, access) {
10502
11041
  lowerUnionObjectDynFieldCall(lowerer, call, access, mappedReceiver);
10503
11042
  if (dispatched)
10504
11043
  return dispatched;
11044
+ const arms = lowerer.unions.get(mappedReceiver.unionId)?.arms;
11045
+ if (isJsSourceFile(call.getSourceFile()) && arms?.every((arm) => arm.kind === "object" &&
11046
+ !lowerer.classes.get(arm.className)?.def.runtime) && lowerer.dynConvertible(mappedReceiver)) {
11047
+ return lowerDynReceiverMethodCall(lowerer, call, access);
11048
+ }
10505
11049
  }
10506
11050
  const receiverIr = mappedReceiver?.kind === "object"
10507
11051
  ? mappedReceiver
@@ -10614,6 +11158,21 @@ export function lowerObjectMethodCall(lowerer, call, access) {
10614
11158
  return finish({ kind: "dynCall", callee, receiver, calleeName: access.getText(), args, type: DYN, loc });
10615
11159
  }
10616
11160
  }
11161
+ if (!fieldType && isJsSourceFile(call.getSourceFile()) && !info.def.runtime && !info.builtinError && !info.builtinEmitter && !info.builtinStream) {
11162
+ const loc = locOf(call);
11163
+ const value = lowerReceiver();
11164
+ const local = lowerer.declareHiddenLocal("%callReceiver", value.type);
11165
+ const reference = { kind: "varRef", localId: local.id, type: value.type, loc };
11166
+ const receiver = lowerer.coerceToExpected(reference, DYN);
11167
+ const callee = { kind: "dynKeyGet", value: receiver,
11168
+ key: { kind: "strLit", value: access.name.text, type: STRING, loc }, type: DYN, loc };
11169
+ const spread = call.arguments.some(ts.isSpreadElement) ? lowerSpreadArgsCall(lowerer, call, callee, loc) : null;
11170
+ if (spread && spread.kind !== "dynCall")
11171
+ lowerer.unsupported("SC1090", call, "native property call spread arguments");
11172
+ const result = spread !== null ? { ...spread, receiver } : { kind: "dynCall", callee, receiver,
11173
+ calleeName: access.getText(), args: call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
11174
+ return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id, init: value, loc }], result, type: DYN, loc };
11175
+ }
10617
11176
  return null;
10618
11177
  }
10619
11178
  if (!info || !found)
@@ -10633,7 +11192,7 @@ export function lowerObjectMethodCall(lowerer, call, access) {
10633
11192
  const fallback = virtual
10634
11193
  ? { kind: "virtualCall", className: info.def.name, method, args: [lowerer.upcastTo(value, info.def.name), ...args], type: found.sig.ret, loc }
10635
11194
  : { kind: "call", callee: `%${found.declarer.def.name}.${method}`, args: [lowerer.upcastTo(value, found.declarer.def.name), ...args], type: found.sig.ret, loc };
10636
- const result = classCallbackCall(lowerer, value, method, call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), fallback, loc);
11195
+ const result = classCallbackCall(lowerer, value, method, call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), fallback, loc, access.getText());
10637
11196
  return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id, init: receiver, loc }], result, type: result.type, loc };
10638
11197
  }
10639
11198
  if (found.declarer.builtinError) {
@@ -10696,6 +11255,22 @@ function lowerUnionObjectMethodCall(lowerer, call, access, receiverT) {
10696
11255
  plans.push({ arm, info, found });
10697
11256
  }
10698
11257
  const shapes = plans[0].found.sig.params;
11258
+ if (plans.some((plan) => isClassCallback(lowerer, plan.info, method))) {
11259
+ const loc = locOf(call);
11260
+ const local = lowerer.declareHiddenLocal("%unionMethodReceiver", DYN);
11261
+ const receiver = varRef(local.id, DYN, loc);
11262
+ const callee = { kind: "dynKeyGet", value: receiver,
11263
+ key: { kind: "strLit", value: method, type: STRING, loc }, type: DYN, loc };
11264
+ const spread = call.arguments.some(ts.isSpreadElement) ? lowerSpreadArgsCall(lowerer, call, callee, loc) : null;
11265
+ if (spread && spread.kind !== "dynCall")
11266
+ lowerer.unsupported("SC1090", call, "union method spread arguments");
11267
+ const value = spread !== null ? { ...spread, receiver } : { kind: "dynCall", callee, receiver,
11268
+ calleeName: access.getText(), args: call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
11269
+ const resultT = lowerer.mapTypeOf(lowerer.typeOf(call));
11270
+ const result = resultT && !isUnitType(resultT) ? lowerer.coerceToExpected(value, resultT) : value;
11271
+ return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id,
11272
+ init: lowerer.coerceInto(access.expression, lowerer.lowerExpr(access.expression), DYN), loc }], result, type: result.type, loc };
11273
+ }
10699
11274
  if (!plans.every((plan) => paramAbisEqual(shapes, plan.found.sig.params)))
10700
11275
  return null;
10701
11276
  const resultT = lowerer.mapTypeOf(lowerer.typeOf(call));