@scriptc/compiler 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (315) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +158 -31
  2. package/dist/backend/cycle-analysis.js +63 -50
  3. package/dist/backend/cycle-analysis.js.map +1 -1
  4. package/dist/backend/cycle-analysis.test.js +51 -0
  5. package/dist/backend/cycle-analysis.test.js.map +1 -1
  6. package/dist/backend/llvm/borrowed-receivers.d.ts +9 -0
  7. package/dist/backend/llvm/borrowed-receivers.js +58 -0
  8. package/dist/backend/llvm/borrowed-receivers.js.map +1 -0
  9. package/dist/backend/llvm/call-lifetimes.d.ts +20 -0
  10. package/dist/backend/llvm/call-lifetimes.js +179 -0
  11. package/dist/backend/llvm/call-lifetimes.js.map +1 -0
  12. package/dist/backend/llvm/call-lifetimes.test.d.ts +1 -0
  13. package/dist/backend/llvm/call-lifetimes.test.js +205 -0
  14. package/dist/backend/llvm/call-lifetimes.test.js.map +1 -0
  15. package/dist/backend/llvm/dyn.d.ts +5 -2
  16. package/dist/backend/llvm/dyn.js +163 -47
  17. package/dist/backend/llvm/dyn.js.map +1 -1
  18. package/dist/backend/llvm/emitter.d.ts +37 -1
  19. package/dist/backend/llvm/emitter.js +209 -21
  20. package/dist/backend/llvm/emitter.js.map +1 -1
  21. package/dist/backend/llvm/emitter.test.js +29 -2
  22. package/dist/backend/llvm/emitter.test.js.map +1 -1
  23. package/dist/backend/llvm/expr-async.js +1 -1
  24. package/dist/backend/llvm/expr-async.js.map +1 -1
  25. package/dist/backend/llvm/expr-calls.js +42 -5
  26. package/dist/backend/llvm/expr-calls.js.map +1 -1
  27. package/dist/backend/llvm/expr-containers.js +75 -13
  28. package/dist/backend/llvm/expr-containers.js.map +1 -1
  29. package/dist/backend/llvm/expr-dynamic.js +31 -6
  30. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  31. package/dist/backend/llvm/expr-primitives.js +6 -5
  32. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  33. package/dist/backend/llvm/expr-records.js +1 -1
  34. package/dist/backend/llvm/expr-records.js.map +1 -1
  35. package/dist/backend/llvm/expr-stream-bridges.js +75 -19
  36. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  37. package/dist/backend/llvm/expr-stream-callbacks.d.ts +2 -2
  38. package/dist/backend/llvm/expr-stream-callbacks.js +7 -57
  39. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
  40. package/dist/backend/llvm/lib-dispatch.js +41 -3
  41. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  42. package/dist/backend/llvm/lib-filesystem.js +12 -9
  43. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  44. package/dist/backend/llvm/lib-shared.js +70 -2
  45. package/dist/backend/llvm/lib-shared.js.map +1 -1
  46. package/dist/backend/llvm/local-array-reads.d.ts +44 -0
  47. package/dist/backend/llvm/local-array-reads.js +313 -0
  48. package/dist/backend/llvm/local-array-reads.js.map +1 -0
  49. package/dist/backend/llvm/local-array-reads.test.d.ts +1 -0
  50. package/dist/backend/llvm/local-array-reads.test.js +446 -0
  51. package/dist/backend/llvm/local-array-reads.test.js.map +1 -0
  52. package/dist/backend/llvm/map-read-lifetimes.d.ts +36 -0
  53. package/dist/backend/llvm/map-read-lifetimes.js +128 -0
  54. package/dist/backend/llvm/map-read-lifetimes.js.map +1 -0
  55. package/dist/backend/llvm/map-read-lifetimes.test.d.ts +1 -0
  56. package/dist/backend/llvm/map-read-lifetimes.test.js +123 -0
  57. package/dist/backend/llvm/map-read-lifetimes.test.js.map +1 -0
  58. package/dist/backend/llvm/shapes.js +1 -0
  59. package/dist/backend/llvm/shapes.js.map +1 -1
  60. package/dist/backend/llvm/split.js +15 -5
  61. package/dist/backend/llvm/split.js.map +1 -1
  62. package/dist/backend/llvm/split.test.js +17 -0
  63. package/dist/backend/llvm/split.test.js.map +1 -1
  64. package/dist/backend/llvm/stack-unions.d.ts +20 -0
  65. package/dist/backend/llvm/stack-unions.js +61 -0
  66. package/dist/backend/llvm/stack-unions.js.map +1 -0
  67. package/dist/backend/llvm/stack-unions.test.d.ts +1 -0
  68. package/dist/backend/llvm/stack-unions.test.js +241 -0
  69. package/dist/backend/llvm/stack-unions.test.js.map +1 -0
  70. package/dist/backend/llvm/string-lifetimes.d.ts +12 -0
  71. package/dist/backend/llvm/string-lifetimes.js +70 -0
  72. package/dist/backend/llvm/string-lifetimes.js.map +1 -0
  73. package/dist/backend/llvm/string-lifetimes.test.d.ts +1 -0
  74. package/dist/backend/llvm/string-lifetimes.test.js +230 -0
  75. package/dist/backend/llvm/string-lifetimes.test.js.map +1 -0
  76. package/dist/backend/mangle.d.ts +2 -0
  77. package/dist/backend/mangle.js +4 -0
  78. package/dist/backend/mangle.js.map +1 -1
  79. package/dist/backend/may-throw.js +71 -29
  80. package/dist/backend/may-throw.js.map +1 -1
  81. package/dist/backend/may-throw.test.js +104 -1
  82. package/dist/backend/may-throw.test.js.map +1 -1
  83. package/dist/backend/native-codegen.d.ts +1 -1
  84. package/dist/backend/native-codegen.js +4 -3
  85. package/dist/backend/native-codegen.js.map +1 -1
  86. package/dist/backend/native-codegen.test.js +11 -0
  87. package/dist/backend/native-codegen.test.js.map +1 -1
  88. package/dist/backend/native-toolchain.d.ts +2 -2
  89. package/dist/backend/native-toolchain.js +2 -0
  90. package/dist/backend/native-toolchain.js.map +1 -1
  91. package/dist/backend/target-diagnostics.d.ts +5 -0
  92. package/dist/backend/target-diagnostics.js +72 -1
  93. package/dist/backend/target-diagnostics.js.map +1 -1
  94. package/dist/backend/target-diagnostics.test.d.ts +1 -0
  95. package/dist/backend/target-diagnostics.test.js +68 -0
  96. package/dist/backend/target-diagnostics.test.js.map +1 -0
  97. package/dist/coverage/surface-manifest.js +5 -3
  98. package/dist/coverage/surface-manifest.js.map +1 -1
  99. package/dist/executable/executable-cache.d.ts +7 -3
  100. package/dist/executable/executable-cache.js +47 -11
  101. package/dist/executable/executable-cache.js.map +1 -1
  102. package/dist/executable/executable-cache.test.js +109 -2
  103. package/dist/executable/executable-cache.test.js.map +1 -1
  104. package/dist/executable/prepare.js +2 -1
  105. package/dist/executable/prepare.js.map +1 -1
  106. package/dist/frontend/builtin-modules.d.ts +1 -1
  107. package/dist/frontend/builtin-modules.js +1 -1
  108. package/dist/frontend/builtin-modules.js.map +1 -1
  109. package/dist/frontend/function-completion.d.ts +6 -0
  110. package/dist/frontend/function-completion.js +50 -0
  111. package/dist/frontend/function-completion.js.map +1 -0
  112. package/dist/frontend/input-tracker.js +3 -3
  113. package/dist/frontend/input-tracker.js.map +1 -1
  114. package/dist/frontend/input-tracker.test.js +38 -2
  115. package/dist/frontend/input-tracker.test.js.map +1 -1
  116. package/dist/frontend/lowering/abstract-equality.js +5 -1
  117. package/dist/frontend/lowering/abstract-equality.js.map +1 -1
  118. package/dist/frontend/lowering/checked-iterable-spread.d.ts +4 -0
  119. package/dist/frontend/lowering/checked-iterable-spread.js +30 -0
  120. package/dist/frontend/lowering/checked-iterable-spread.js.map +1 -0
  121. package/dist/frontend/lowering/checked-promise-all.d.ts +5 -0
  122. package/dist/frontend/lowering/checked-promise-all.js +31 -0
  123. package/dist/frontend/lowering/checked-promise-all.js.map +1 -0
  124. package/dist/frontend/lowering/class-callbacks.d.ts +1 -1
  125. package/dist/frontend/lowering/class-callbacks.js +7 -6
  126. package/dist/frontend/lowering/class-callbacks.js.map +1 -1
  127. package/dist/frontend/lowering/class-construction.d.ts +2 -0
  128. package/dist/frontend/lowering/class-construction.js +34 -5
  129. package/dist/frontend/lowering/class-construction.js.map +1 -1
  130. package/dist/frontend/lowering/class-descriptors.d.ts +1 -1
  131. package/dist/frontend/lowering/class-descriptors.js +12 -5
  132. package/dist/frontend/lowering/class-descriptors.js.map +1 -1
  133. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +25 -0
  134. package/dist/frontend/lowering/class-dynamic-dispatch.js +597 -78
  135. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  136. package/dist/frontend/lowering/class-dynamic-dispatch.test.js +64 -2
  137. package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
  138. package/dist/frontend/lowering/class-instance-constructor.d.ts +1 -1
  139. package/dist/frontend/lowering/class-instance-constructor.js +11 -41
  140. package/dist/frontend/lowering/class-instance-constructor.js.map +1 -1
  141. package/dist/frontend/lowering/class-method-values.d.ts +16 -0
  142. package/dist/frontend/lowering/class-method-values.js +60 -29
  143. package/dist/frontend/lowering/class-method-values.js.map +1 -1
  144. package/dist/frontend/lowering/class-prototypes.d.ts +5 -1
  145. package/dist/frontend/lowering/class-prototypes.js +69 -10
  146. package/dist/frontend/lowering/class-prototypes.js.map +1 -1
  147. package/dist/frontend/lowering/class-runtime-statics.d.ts +4 -4
  148. package/dist/frontend/lowering/class-runtime-statics.js +26 -8
  149. package/dist/frontend/lowering/class-runtime-statics.js.map +1 -1
  150. package/dist/frontend/lowering/class-static-data.d.ts +1 -0
  151. package/dist/frontend/lowering/class-static-data.js +4 -2
  152. package/dist/frontend/lowering/class-static-data.js.map +1 -1
  153. package/dist/frontend/lowering/collection-ingestion.d.ts +31 -0
  154. package/dist/frontend/lowering/collection-ingestion.js +215 -0
  155. package/dist/frontend/lowering/collection-ingestion.js.map +1 -0
  156. package/dist/frontend/lowering/containers/bytes.js +19 -4
  157. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  158. package/dist/frontend/lowering/containers/string-and-regexp.js +6 -1
  159. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  160. package/dist/frontend/lowering/deferred-module-initializers.d.ts +13 -0
  161. package/dist/frontend/lowering/deferred-module-initializers.js +410 -0
  162. package/dist/frontend/lowering/deferred-module-initializers.js.map +1 -0
  163. package/dist/frontend/lowering/deferred-module-initializers.test.d.ts +1 -0
  164. package/dist/frontend/lowering/deferred-module-initializers.test.js +92 -0
  165. package/dist/frontend/lowering/deferred-module-initializers.test.js.map +1 -0
  166. package/dist/frontend/lowering/expressions/object-literals.js +31 -1
  167. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  168. package/dist/frontend/lowering/expressions/optional-chains.js +3 -3
  169. package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
  170. package/dist/frontend/lowering/import-meta.d.ts +10 -0
  171. package/dist/frontend/lowering/import-meta.js +52 -0
  172. package/dist/frontend/lowering/import-meta.js.map +1 -0
  173. package/dist/frontend/lowering/lower-assert.js +105 -41
  174. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  175. package/dist/frontend/lowering/lower-builtin-values.d.ts +2 -0
  176. package/dist/frontend/lowering/lower-builtin-values.js +22 -1
  177. package/dist/frontend/lowering/lower-builtin-values.js.map +1 -1
  178. package/dist/frontend/lowering/lower-builtins.d.ts +7 -22
  179. package/dist/frontend/lowering/lower-builtins.js +439 -95
  180. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  181. package/dist/frontend/lowering/lower-calls.js +289 -76
  182. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  183. package/dist/frontend/lowering/lower-classes.d.ts +5 -0
  184. package/dist/frontend/lowering/lower-classes.js +443 -29
  185. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  186. package/dist/frontend/lowering/lower-containers.d.ts +6 -2
  187. package/dist/frontend/lowering/lower-containers.js +79 -20
  188. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  189. package/dist/frontend/lowering/lower-exprs.d.ts +10 -6
  190. package/dist/frontend/lowering/lower-exprs.js +329 -170
  191. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  192. package/dist/frontend/lowering/lower-generators.js +5 -1
  193. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  194. package/dist/frontend/lowering/lower-inspect.js +58 -1
  195. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  196. package/dist/frontend/lowering/lower-island.js +4 -0
  197. package/dist/frontend/lowering/lower-island.js.map +1 -1
  198. package/dist/frontend/lowering/lower-island.test.d.ts +1 -0
  199. package/dist/frontend/lowering/lower-island.test.js +51 -0
  200. package/dist/frontend/lowering/lower-island.test.js.map +1 -0
  201. package/dist/frontend/lowering/lower-modules.d.ts +1 -3
  202. package/dist/frontend/lowering/lower-modules.js +186 -82
  203. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  204. package/dist/frontend/lowering/lower-modules.test.js +69 -1
  205. package/dist/frontend/lowering/lower-modules.test.js.map +1 -1
  206. package/dist/frontend/lowering/lower-stmts.js +172 -103
  207. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  208. package/dist/frontend/lowering/lower-stmts.test.d.ts +1 -0
  209. package/dist/frontend/lowering/lower-stmts.test.js +77 -0
  210. package/dist/frontend/lowering/lower-stmts.test.js.map +1 -0
  211. package/dist/frontend/lowering/lower-stream.js +2 -0
  212. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  213. package/dist/frontend/lowering/lower-system-errors.d.ts +6 -0
  214. package/dist/frontend/lowering/lower-system-errors.js +29 -0
  215. package/dist/frontend/lowering/lower-system-errors.js.map +1 -0
  216. package/dist/frontend/lowering/lower-url.d.ts +2 -1
  217. package/dist/frontend/lowering/lower-url.js +32 -9
  218. package/dist/frontend/lowering/lower-url.js.map +1 -1
  219. package/dist/frontend/lowering/lowerer.d.ts +30 -12
  220. package/dist/frontend/lowering/lowerer.js +268 -49
  221. package/dist/frontend/lowering/lowerer.js.map +1 -1
  222. package/dist/frontend/lowering/lowerer.test.js +38 -0
  223. package/dist/frontend/lowering/lowerer.test.js.map +1 -1
  224. package/dist/frontend/lowering/module-namespace-elements.d.ts +7 -0
  225. package/dist/frontend/lowering/module-namespace-elements.js +54 -0
  226. package/dist/frontend/lowering/module-namespace-elements.js.map +1 -0
  227. package/dist/frontend/lowering/object-factory-new.d.ts +4 -3
  228. package/dist/frontend/lowering/object-factory-new.js +27 -14
  229. package/dist/frontend/lowering/object-factory-new.js.map +1 -1
  230. package/dist/frontend/lowering/surfaces.d.ts +3 -2
  231. package/dist/frontend/lowering/surfaces.js +93 -33
  232. package/dist/frontend/lowering/surfaces.js.map +1 -1
  233. package/dist/frontend/lowering/text-decoder-encoding.js +3 -0
  234. package/dist/frontend/lowering/text-decoder-encoding.js.map +1 -1
  235. package/dist/frontend/lowering/text-decoder-encoding.test.js +2 -1
  236. package/dist/frontend/lowering/text-decoder-encoding.test.js.map +1 -1
  237. package/dist/frontend/module-syntax.d.ts +1 -1
  238. package/dist/frontend/module-syntax.js +8 -1
  239. package/dist/frontend/module-syntax.js.map +1 -1
  240. package/dist/frontend/module-syntax.test.js +10 -0
  241. package/dist/frontend/module-syntax.test.js.map +1 -1
  242. package/dist/frontend/npm.d.ts +4 -0
  243. package/dist/frontend/npm.js +86 -33
  244. package/dist/frontend/npm.js.map +1 -1
  245. package/dist/frontend/npm.test.js +103 -0
  246. package/dist/frontend/npm.test.js.map +1 -1
  247. package/dist/frontend/pipeline-native.js +2 -1
  248. package/dist/frontend/pipeline-native.js.map +1 -1
  249. package/dist/frontend/program.js +4 -2
  250. package/dist/frontend/program.js.map +1 -1
  251. package/dist/frontend/services-node.js +3 -2
  252. package/dist/frontend/services-node.js.map +1 -1
  253. package/dist/frontend/services.d.ts +5 -1
  254. package/dist/frontend/services.js +9 -1
  255. package/dist/frontend/services.js.map +1 -1
  256. package/dist/frontend/services.test.js +21 -0
  257. package/dist/frontend/services.test.js.map +1 -1
  258. package/dist/frontend/ts7/ast-node.d.ts +2 -0
  259. package/dist/frontend/ts7/ast-node.js +30 -4
  260. package/dist/frontend/ts7/ast-node.js.map +1 -1
  261. package/dist/frontend/ts7/ast-node.test.js +60 -1
  262. package/dist/frontend/ts7/ast-node.test.js.map +1 -1
  263. package/dist/frontend/type-mapper.js +89 -14
  264. package/dist/frontend/type-mapper.js.map +1 -1
  265. package/dist/frontend/union-discriminants.js +22 -7
  266. package/dist/frontend/union-discriminants.js.map +1 -1
  267. package/dist/index.js +19 -12
  268. package/dist/index.js.map +1 -1
  269. package/dist/ir/analysis.js +1 -0
  270. package/dist/ir/analysis.js.map +1 -1
  271. package/dist/ir/integer-loops.d.ts +7 -0
  272. package/dist/ir/integer-loops.js +23 -0
  273. package/dist/ir/integer-loops.js.map +1 -1
  274. package/dist/ir/integer-loops.test.d.ts +1 -0
  275. package/dist/ir/integer-loops.test.js +41 -0
  276. package/dist/ir/integer-loops.test.js.map +1 -0
  277. package/dist/ir/ir.d.ts +44 -26
  278. package/dist/ir/ir.js +69 -11
  279. package/dist/ir/ir.js.map +1 -1
  280. package/dist/ir/ir.test.js +18 -0
  281. package/dist/ir/ir.test.js.map +1 -1
  282. package/dist/ir/serialize.js +21 -1
  283. package/dist/ir/serialize.js.map +1 -1
  284. package/dist/ir/serialize.test.js +21 -0
  285. package/dist/ir/serialize.test.js.map +1 -1
  286. package/dist/ir/traverse.d.ts +0 -3
  287. package/dist/ir/traverse.js +33 -20
  288. package/dist/ir/traverse.js.map +1 -1
  289. package/dist/ir/validate.js +216 -80
  290. package/dist/ir/validate.js.map +1 -1
  291. package/dist/ir/validate.test.js +244 -1
  292. package/dist/ir/validate.test.js.map +1 -1
  293. package/dist/library/compiler-self-identity.js +1 -1
  294. package/dist/library/compiler-self-identity.test.js +2 -2
  295. package/dist/library/compiler-self-identity.test.js.map +1 -1
  296. package/dist/library/fence-eval.js +9 -2
  297. package/dist/library/fence-eval.js.map +1 -1
  298. package/dist/library/fence-eval.test.d.ts +1 -0
  299. package/dist/library/fence-eval.test.js +21 -0
  300. package/dist/library/fence-eval.test.js.map +1 -0
  301. package/dist/library/int-infer.d.ts +2 -2
  302. package/dist/library/int-infer.js +10 -7
  303. package/dist/library/int-infer.js.map +1 -1
  304. package/dist/library/int-infer.test.js +44 -0
  305. package/dist/library/int-infer.test.js.map +1 -1
  306. package/dist/library/prepare.js +2 -1
  307. package/dist/library/prepare.js.map +1 -1
  308. package/dist/native/runtime-typescript.d.ts +4 -0
  309. package/dist/native/runtime-typescript.js +61 -0
  310. package/dist/native/runtime-typescript.js.map +1 -0
  311. package/dist/native/runtime-typescript.test.d.ts +1 -0
  312. package/dist/native/runtime-typescript.test.js +41 -0
  313. package/dist/native/runtime-typescript.test.js.map +1 -0
  314. package/package.json +20 -20
  315. package/surface-manifest.json +385 -29
@@ -10,7 +10,7 @@ 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";
@@ -45,6 +45,9 @@ import { fenceSymbolFieldCopy } from "./symbol-fields.js";
45
45
  import { lowerClassDataDescriptor, lowerClassDescriptorRead } from "./class-descriptors.js";
46
46
  import { classStaticDataFor } from "./class-static-data.js";
47
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";
48
51
  export { bodyReadsArguments };
49
52
  /** The one func-type projection of completed parameter shapes. Typed rest
50
53
  * parameters keep their packed array as the trailing native ABI slot and
@@ -125,6 +128,23 @@ export const MAX_GENERIC_INSTANCES = 100;
125
128
  * - `...xs: T[]`: the ABI type is the array; call sites pack the surplus.
126
129
  */
127
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
+ }
128
148
  if (param.initializer && isJsSourceFile(param.getSourceFile()) && !param.type &&
129
149
  !/@(?:param|type)\b/.test(param.getSourceFile().text.slice(param.parent?.pos ?? param.pos, param.getStart()))) {
130
150
  return { type: DYN, mode: "omittable", bodyType: DYN };
@@ -219,9 +239,39 @@ export function paramShape(lowerer, param) {
219
239
  }
220
240
  if (param.initializer) {
221
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
+ }
222
249
  return defaultParameterShape(lowerer, param, raw);
223
250
  }
224
- 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
+ }
225
275
  if (type.kind === "void") {
226
276
  return { type: DYN, mode: param.questionToken ? "omittable" : "required" };
227
277
  }
@@ -249,8 +299,9 @@ export function isThisParameter(param) {
249
299
  export function paramShapes(lowerer, params, signature, blameOf) {
250
300
  if (!signature)
251
301
  return params.filter((p) => !isThisParameter(p)).map((param) => lowerer.paramShape(param));
302
+ const symbols = signature.getParameters();
252
303
  return params.map((declParam, i) => {
253
- const symbol = signature.getParameters()[i];
304
+ const symbol = symbols[i];
254
305
  const tsType = symbol ? lowerer.checker.getTypeOfSymbol(symbol) : lowerer.typeOf(declParam.name);
255
306
  const mapped = jsOpenObjectType(declParam, lowerer.runtimeOptionalBindingType(declParam.name, lowerer.mapTypeOf(tsType) ?? lowerer.irTypeOf(declParam.name)), lowerer.shapes, lowerer.unions);
256
307
  if (!mapped || mapped.kind === "void")
@@ -368,7 +419,7 @@ leading) {
368
419
  // before conversion to the dense checked-dynamic argument pack.
369
420
  value = { kind: "arrayLit", elems: [value], spreads: [0], type: value.type, loc: value.loc };
370
421
  }
371
- value = lowerer.coerceInto(arg.expression, value, DYN);
422
+ value = checkedIterableSpread(lowerer, value, arg.expression.getText(), loc);
372
423
  if (spreads === 1 && index === argNodes.length - 1) {
373
424
  stmts.push({ kind: "exprStmt", expr: {
374
425
  kind: "libCall", fn: "dyn.packPushSpread", args: [ref(), value, { kind: "strLit", value: arg.expression.getText(), type: STRING, loc }], type: VOID, loc,
@@ -892,6 +943,8 @@ function producesConstructor(lowerer, type) {
892
943
  return false;
893
944
  }
894
945
  export function declaredReturnType(lowerer, decl, blame) {
946
+ if (isJsSourceFile(decl.getSourceFile()) && ts.isGetAccessorDeclaration(decl))
947
+ return DYN;
895
948
  const sig = lowerer.checker.getSignatureFromDeclaration(decl);
896
949
  if (!sig)
897
950
  lowerer.unsupported("SC1090", decl, "this function form");
@@ -906,11 +959,36 @@ export function declaredReturnType(lowerer, decl, blame) {
906
959
  // (`.action(() => { throw ... })`). `never` VALUES stay unmapped.
907
960
  if (retTsType.flags & ts.TypeFlags.Never)
908
961
  return VOID;
909
- const mappedReturn = lowerer.mapTypeOf(retTsType);
910
- if (isJsSourceFile(decl.getSourceFile()) && mappedReturn?.kind === "array" && mappedReturn.elem.kind === "f64")
962
+ let mappedReturn = lowerer.mapTypeOf(retTsType);
963
+ if (isJsSourceFile(decl.getSourceFile()) && decl.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword) &&
964
+ !decl.asteriskToken && mappedReturn?.kind !== "promise") {
965
+ const fallback = dynFallbackType(lowerer, decl, retTsType);
966
+ return fallback?.kind === "promise" ? fallback : { kind: "promise", inner: DYN };
967
+ }
968
+ if (mappedReturn && isJsSourceFile(decl.getSourceFile()) && functionCanReturnUndefined(decl))
969
+ mappedReturn = lowerer.withUndefinedArmOf(mappedReturn) ?? mappedReturn;
970
+ if (isJsSourceFile(decl.getSourceFile()) && mappedReturn?.kind === "void") {
971
+ let returnsValue = false;
972
+ const scan = (node) => {
973
+ if (node !== decl && ts.isFunctionLike(node))
974
+ return;
975
+ if (ts.isReturnStatement(node) && node.expression)
976
+ returnsValue = true;
977
+ node.forEachChild(scan);
978
+ };
979
+ scan(decl);
980
+ if (returnsValue)
981
+ return DYN;
982
+ }
983
+ if (isJsSourceFile(decl.getSourceFile()) && mappedReturn?.kind === "array")
984
+ return DYN;
985
+ if (isJsSourceFile(decl.getSourceFile()) && !decl.type && !hasExplicitJsDocReturn(decl) && mappedReturn?.kind === "record")
911
986
  return DYN;
912
987
  if (isJsSourceFile(decl.getSourceFile()) && !decl.type && !hasExplicitJsDocReturn(decl) && mappedReturn?.kind === "date")
913
988
  return DYN;
989
+ if (isJsSourceFile(decl.getSourceFile()) && !decl.type && !hasExplicitJsDocReturn(decl) &&
990
+ mappedReturn?.kind === "union" && lowerer.unions.get(mappedReturn.unionId)?.arms.some((arm) => arm.kind === "func"))
991
+ return DYN;
914
992
  // JS inference assigns Number to arithmetic over any, although the
915
993
  // runtime operands can both be BigInts. Preserve that native result.
916
994
  if (isJsSourceFile(decl.getSourceFile()) && !decl.type && !hasExplicitJsDocReturn(decl) &&
@@ -971,7 +1049,7 @@ export function declaredReturnType(lowerer, decl, blame) {
971
1049
  // Native-only members (such as Int32Array layout offsets) cannot cross
972
1050
  // that boundary; their factories keep the native record ABI.
973
1051
  const asyncReturn = decl.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword) && mappedReturn?.kind === "promise";
974
- const recordReturn = asyncReturn ? mappedReturn.inner : mappedReturn;
1052
+ const recordReturn = asyncReturn && mappedReturn?.kind === "promise" ? mappedReturn.inner : mappedReturn;
975
1053
  const recordArms = recordReturn?.kind === "union" ? lowerer.unions.get(recordReturn.unionId)?.arms : recordReturn ? [recordReturn] : undefined;
976
1054
  const inferredRecordReturn = recordArms?.some((arm) => arm.kind === "record" || arm.kind === "object") &&
977
1055
  recordArms.every((arm) => isUnitType(arm) || arm.kind === "record" || arm.kind === "object" && !hasExplicitJsDocReturn(decl));
@@ -985,7 +1063,7 @@ export function declaredReturnType(lowerer, decl, blame) {
985
1063
  })) {
986
1064
  return asyncReturn ? { kind: "promise", inner: DYN } : DYN;
987
1065
  }
988
- const returnType = lowerer.mapTypeOf(retTsType);
1066
+ const returnType = mappedReturn;
989
1067
  if (!returnType) {
990
1068
  // JS inference residue (an `any` return, an unmappable union): the
991
1069
  // checked-dynamic fallback, exactly the declaration story in
@@ -1466,8 +1544,9 @@ function unifySignatureBindings(lowerer, info, rsig, bindings, tsBindings) {
1466
1544
  if (dSigs.length === 1 && iSigs.length === 1) {
1467
1545
  const ds = dSigs[0];
1468
1546
  const is = iSigs[0];
1547
+ const instanceParams = is.getParameters();
1469
1548
  ds.getParameters().forEach((dp, i) => {
1470
- const ip = is.getParameters()[i];
1549
+ const ip = instanceParams[i];
1471
1550
  if (ip)
1472
1551
  unify(lowerer.checker.getTypeOfSymbol(dp), lowerer.checker.getTypeOfSymbol(ip), depth + 1);
1473
1552
  });
@@ -1484,8 +1563,9 @@ function unifySignatureBindings(lowerer, info, rsig, bindings, tsBindings) {
1484
1563
  };
1485
1564
  const declSig = lowerer.checker.getSignatureFromDeclaration(info.decl);
1486
1565
  if (declSig) {
1566
+ const instanceParams = rsig.getParameters();
1487
1567
  declSig.getParameters().forEach((dp, i) => {
1488
- const ip = rsig.getParameters()[i];
1568
+ const ip = instanceParams[i];
1489
1569
  if (ip)
1490
1570
  unify(lowerer.checker.getTypeOfSymbol(dp), lowerer.checker.getTypeOfSymbol(ip));
1491
1571
  });
@@ -2097,6 +2177,12 @@ function implicitDeclaredReturn(lowerer, info) {
2097
2177
  if (retTs.flags & (ts.TypeFlags.Null | ts.TypeFlags.Undefined))
2098
2178
  return DYN;
2099
2179
  if (lowerer.checker.isArrayType(retTs)) {
2180
+ // Inferred JavaScript arrays can hold values selected through a
2181
+ // mutable constructor registry. The checker may retain only one
2182
+ // constructor's element type; settle the result from the lowered
2183
+ // container instead of checking every element against that guess.
2184
+ if (!hasExplicitJsDocReturn(info.decl))
2185
+ return null;
2100
2186
  if (info.decl.parameters.some((param, index) => info.implicitParams?.[index] &&
2101
2187
  lowerer.mapTypeOf(lowerer.typeOf(param.name))?.kind === "array"))
2102
2188
  return null;
@@ -2110,6 +2196,12 @@ function implicitDeclaredReturn(lowerer, info) {
2110
2196
  return null;
2111
2197
  }
2112
2198
  const mapped = lowerer.mapTypeOf(retTs);
2199
+ // Mixed inferred results can select a closure or a class instance.
2200
+ // Their callable ABI is settled by the lowered body, including native
2201
+ // classes whose reflected calls return checked values.
2202
+ if (mapped?.kind === "union" && !hasExplicitJsDocReturn(info.decl) &&
2203
+ lowerer.unions.get(mapped.unionId)?.arms.some((arm) => arm.kind === "func"))
2204
+ return null;
2113
2205
  if (mapped?.kind === "symbol" && !hasExplicitJsDocReturn(info.decl))
2114
2206
  return null;
2115
2207
  if (mapped?.kind === "date" && !hasExplicitJsDocReturn(info.decl))
@@ -2206,12 +2298,25 @@ function storedImplicitArgumentType(lowerer, arg) {
2206
2298
  return DYN;
2207
2299
  if (ts.isIdentifier(arg))
2208
2300
  return lowerer.peekLocal(arg)?.type ?? lowerer.globalOf(arg)?.type ?? null;
2301
+ if (isJsSourceFile(arg.getSourceFile()) &&
2302
+ (ts.isPropertyAccessExpression(arg) || ts.isElementAccessExpression(arg))) {
2303
+ // Mutable JS members can retain an initializer-only checker type (for
2304
+ // example a linked-list slot initially null). Specialize to the value
2305
+ // we actually represent, rather than checking it back into that type.
2306
+ const represented = tryLowerExpression(lowerer, arg);
2307
+ if (represented)
2308
+ return represented.type;
2309
+ }
2310
+ if (isJsSourceFile(arg.getSourceFile()) && (ts.isCallExpression(arg) || ts.isConditionalExpression(arg) ||
2311
+ ts.isBinaryExpression(arg) && (arg.operatorToken.kind === ts.SyntaxKind.BarBarToken ||
2312
+ arg.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken || arg.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken))) {
2313
+ // Calls and fallback expressions can retain checked storage wider than
2314
+ // the checker's inference (for example Object.assign on a JS instance).
2315
+ const represented = tryLowerExpression(lowerer, arg);
2316
+ if (represented?.type.kind === "dyn" || represented?.type.kind === "func")
2317
+ return represented.type;
2318
+ }
2209
2319
  if (ts.isCallExpression(arg) && ts.isIdentifier(arg.expression)) {
2210
- if (isJsSourceFile(arg.getSourceFile())) {
2211
- const represented = tryLowerExpression(lowerer, arg);
2212
- if (represented?.type.kind === "dyn" || represented?.type.kind === "func")
2213
- return represented.type;
2214
- }
2215
2320
  const callee = storedImplicitArgumentType(lowerer, arg.expression);
2216
2321
  if (callee?.kind === "dyn")
2217
2322
  return DYN;
@@ -3852,6 +3957,7 @@ export function lowerCall(lowerer, expr) {
3852
3957
  lowerer.fenceStaticReadableStreamMember(access, "call");
3853
3958
  const source = tryLowerExpression(lowerer, access.expression);
3854
3959
  if (source && (source.type.kind === "dyn" || source.type.kind === "func" ||
3960
+ source.type.kind === "union" && isJsSourceFile(expr.getSourceFile()) && lowerer.dynConvertible(source.type) ||
3855
3961
  (source.type.kind === "map" || source.type.kind === "set") && lowerer.dynConvertible(source.type) || isDynTypedRefType(source.type) &&
3856
3962
  lowerer.foldedStringKeyOf(access.argumentExpression) === null &&
3857
3963
  lowerer.mapTypeOf(lowerer.typeOf(access.argumentExpression))?.kind !== "symbol")) {
@@ -4238,6 +4344,9 @@ export function lowerCall(lowerer, expr) {
4238
4344
  if (name === "parseFloat" && probed?.type.kind === "string") {
4239
4345
  return { kind: "libCall", fn: "num.parseFloat", args: [probed], type: F64, loc };
4240
4346
  }
4347
+ if (name === "parseFloat" && probed?.type.kind === "dyn") {
4348
+ return { kind: "libCall", fn: "num.parseFloat", args: [{ kind: "libCall", fn: "dyn.toStringCoerce", args: [probed], type: STRING, loc }], type: F64, loc };
4349
+ }
4241
4350
  if (name === "isFinite" && probed?.type.kind === "f64") {
4242
4351
  return { kind: "libCall", fn: "number.isFinite", args: [probed], type: BOOL, loc };
4243
4352
  }
@@ -4565,6 +4674,7 @@ export function lowerCall(lowerer, expr) {
4565
4674
  // Before the island path: regex-argument replace/replaceAll/split
4566
4675
  // lower STATICALLY; only the string-pattern overloads are island.
4567
4676
  lowerRegexMethodCallWithOptionalArg(lowerer, expr, expr.expression) ??
4677
+ lowerUrlStaticCall(lowerer, expr, expr.expression) ??
4568
4678
  lowerer.lowerUrlMethodCall(expr, expr.expression) ??
4569
4679
  lowerer.lowerSearchParamsMethodCall(expr, expr.expression) ??
4570
4680
  lowerer.lowerStatsMethodCall(expr, expr.expression) ??
@@ -4615,9 +4725,6 @@ export function lowerCall(lowerer, expr) {
4615
4725
  lowerer.lowerBytesMethodCall(expr, expr.expression) ??
4616
4726
  lowerBytesStaticCall(lowerer, expr, expr.expression) ??
4617
4727
  lowerBufferStaticCallWithNarrowedArg(lowerer, expr, expr.expression) ??
4618
- // URL.revokeObjectURL's zero-argument contract (the one-argument
4619
- // form keeps the fence — createObjectURL does too).
4620
- lowerUrlStaticCall(lowerer, expr, expr.expression) ??
4621
4728
  // Readable.from — the stream classes' one static (before the
4622
4729
  // stdlib chokepoint claims the member).
4623
4730
  lowerStreamStaticCall(lowerer, expr, expr.expression) ??
@@ -5760,7 +5867,7 @@ function lowerSpreadArgsCall(lowerer, expr, callee, loc) {
5760
5867
  // The spelling rides along for V8's nullish spread-call
5761
5868
  // TypeError ("v is not iterable (cannot read property ...)").
5762
5869
  spreads.push({ arg: args.length, what: p.spreadOf.getText() });
5763
- args.push(lowerer.coerceInto(p.spreadOf, p.v, DYN));
5870
+ args.push(checkedIterableSpread(lowerer, p.v, p.spreadOf.getText(), loc));
5764
5871
  }
5765
5872
  else {
5766
5873
  args.push(lowerer.coerceInto(p.node, p.v, DYN));
@@ -5770,7 +5877,7 @@ function lowerSpreadArgsCall(lowerer, expr, callee, loc) {
5770
5877
  return { kind: "dynCall", callee: boxed, calleeName, args, spreads, type: DYN, loc };
5771
5878
  }
5772
5879
  if (spreadParts.length > 0 &&
5773
- spreadParts.every((p) => p.v.type.kind === "jsval") &&
5880
+ (spreadParts.every((p) => p.v.type.kind === "jsval") || callee.type.kind === "func" && callee.type.restAbi === "jsval") &&
5774
5881
  (callee.type.kind === "jsval" || callee.type.kind === "func")) {
5775
5882
  if (spreadParts.length !== 1 || parts[parts.length - 1].spreadOf === null) {
5776
5883
  lowerer.unsupported("SC1090", expr, "spread arguments before positional arguments in island calls (one trailing spread after the fixed arguments is the supported form)");
@@ -5783,7 +5890,7 @@ function lowerSpreadArgsCall(lowerer, expr, callee, loc) {
5783
5890
  const last = parts[parts.length - 1];
5784
5891
  // The spelling rides in `name` for V8's nullish spread-call
5785
5892
  // TypeError ("v is not iterable (cannot read property ...)").
5786
- return { kind: "jsOp", op: "callSpread", name: last.spreadOf.getText(), args: [f, preArr, last.v], type: JSVAL, loc };
5893
+ return { kind: "jsOp", op: "callSpread", name: last.spreadOf.getText(), args: [f, preArr, lowerer.coerceInto(last.spreadOf, last.v, JSVAL)], type: JSVAL, loc };
5787
5894
  }
5788
5895
  // No lane fits (a spread source outside both tiers, a callee neither
5789
5896
  // boxable nor marshalable, mixed dyn/jsval spreads): fence HERE — the
@@ -5835,12 +5942,21 @@ function canCompleteRuntimeSpread(lowerer, shapes) {
5835
5942
  function lowerDynReceiverMethodCall(lowerer, call, access) {
5836
5943
  if (lowerer.chainBlocked(call, access))
5837
5944
  return null;
5945
+ if (stdlibGlobalNameOf(lowerer, access.expression) !== null)
5946
+ return null;
5838
5947
  // Only checker-untyped receivers: `any`/`unknown`, or the `any[]` an
5839
5948
  // Array.isArray guard narrows them to (the value is STILL the checked-dynamic tree
5840
5949
  // array — scalar narrowings bridge through maybeNarrow's dynCheck and
5841
5950
  // take the ordinary typed paths, but there is no static home for an
5842
5951
  // any-elemented array). Typed receivers keep their own lowerings.
5843
5952
  const recvTs = lowerer.typeOf(access.expression);
5953
+ const recvSymbol = recvTs.getSymbol();
5954
+ if (recvSymbol && ["MapIterator", "SetIterator"].includes(recvSymbol.name) &&
5955
+ lowerer.isStdlibSymbol(recvSymbol) &&
5956
+ ["map", "filter", "take", "drop", "flatMap", "toArray", "forEach", "reduce", "some", "every", "find"].includes(access.name.text) &&
5957
+ lowerer.isStdlibMember(access)) {
5958
+ lowerer.noLowering(`collection iterator .${access.name.text}()`, call, "stored Map/Set iterators support .next() and iteration; iterator helper methods have no lowering");
5959
+ }
5844
5960
  const arrayReceiver = lowerer.checker.isArrayType(recvTs);
5845
5961
  const anyArray = arrayReceiver &&
5846
5962
  ((lowerer.checker.getTypeArguments(recvTs)[0]?.flags ?? 0) &
@@ -5860,7 +5976,7 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
5860
5976
  !["call", "apply", "bind", "toString", "valueOf", "constructor"].includes(access.name.text) &&
5861
5977
  canBoxFuncIntoDyn(probed.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
5862
5978
  const loc = locOf(call);
5863
- const fnName = jsFuncNameOf(access.expression);
5979
+ const fnName = jsFuncNameOf(access.expression, lowerer);
5864
5980
  const boxed = { kind: "dynFrom", value: probed, type: DYN, loc, ...(fnName !== null ? { fnName } : {}) };
5865
5981
  const local = lowerer.declareHiddenLocal("%callableReceiver", DYN);
5866
5982
  const receiver = { kind: "varRef", localId: local.id, type: DYN, loc };
@@ -5879,18 +5995,24 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
5879
5995
  }
5880
5996
  if (probed?.type.kind === "classval") {
5881
5997
  const info = lowerer.classes.get(probed.type.className);
5882
- if (info && (info.callableBase || hasRuntimeStatics(info)))
5998
+ if (info)
5883
5999
  return lowerStaticMethodCall(lowerer, call, access);
5884
6000
  }
5885
- if (probed?.type.kind !== "dyn")
5886
- return null;
5887
- recv = probed;
6001
+ if (probed?.type.kind === "union" && isJsSourceFile(call.getSourceFile()) &&
6002
+ lowerer.unions.get(probed.type.unionId)?.arms.every((arm) => isUnitType(arm) || arm.kind === "object" || arm.kind === "record" || arm.kind === "func") && lowerer.dynConvertible(probed.type)) {
6003
+ recv = lowerer.coerceToExpected(probed, DYN);
6004
+ }
6005
+ else {
6006
+ if (probed?.type.kind !== "dyn")
6007
+ return null;
6008
+ recv = probed;
6009
+ }
5888
6010
  }
5889
6011
  // A factory may return a constructor more precise than its inferred
5890
6012
  // checker result. Runtime static members live on that constructor.
5891
6013
  if (recv.type.kind === "classval") {
5892
6014
  const info = lowerer.classes.get(recv.type.className);
5893
- if (info && (info.callableBase || hasRuntimeStatics(info)))
6015
+ if (info)
5894
6016
  return lowerStaticMethodCall(lowerer, call, access);
5895
6017
  }
5896
6018
  // A checker-`any` receiver that already lowered to a real STRING (the
@@ -5906,6 +6028,25 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
5906
6028
  }
5907
6029
  if (recv.type.kind !== "dyn")
5908
6030
  return null;
6031
+ if (access.name.text === "normalize" && call.arguments.length <= 1 && !call.arguments.some(ts.isSpreadElement)) {
6032
+ const loc = locOf(call);
6033
+ const hasArgument = call.arguments.length === 1;
6034
+ const name = `%dyn.string.normalize:${hasArgument ? 1 : 0}`;
6035
+ if (!lowerer.liftedFns.some((fn) => fn.name === name)) {
6036
+ const value = varRef("receiver", DYN, loc);
6037
+ const argument = varRef("form", DYN, loc);
6038
+ const form = { kind: "ternary", cond: { kind: "dynTest", value: argument, test: "undefined", type: BOOL, loc },
6039
+ then: { kind: "strLit", value: "NFC", type: STRING, loc },
6040
+ else_: { kind: "libCall", fn: "dyn.toStringCoerce", args: [argument], type: STRING, loc }, type: STRING, loc };
6041
+ const result = { kind: "strIntrinsic", method: "normalize", receiver: { kind: "dynCheck", value, type: STRING, loc }, args: [form], type: STRING, loc };
6042
+ lowerer.liftedFns.push({ name, params: [{ localId: "receiver", name: "receiver", type: DYN }, { localId: "form", name: "form", type: DYN }],
6043
+ locals: [{ id: "receiver", name: "receiver", type: DYN, mutable: false }, { id: "form", name: "form", type: DYN, mutable: false }], returnType: DYN, loc,
6044
+ body: [{ kind: "if", cond: { kind: "dynTest", value, test: "string", type: BOOL, loc }, then: [
6045
+ { kind: "return", value: { kind: "dynFrom", value: result, type: DYN, loc }, loc },
6046
+ ], else_: null, loc }, { kind: "return", value: { kind: "dynInvoke", recv: value, method: "normalize", calleeName: access.getText(), args: hasArgument ? [argument] : [], type: DYN, loc }, loc }] });
6047
+ }
6048
+ return { kind: "call", callee: name, args: [recv, call.arguments[0] ? lowerer.lowerExprExpecting(call.arguments[0], DYN) : dynUndefinedExpr(loc)], type: DYN, loc };
6049
+ }
5909
6050
  if (lowerer.mapTypeOf(recvTs)?.kind === "classval") {
5910
6051
  return lowerStaticMethodCall(lowerer, call, access);
5911
6052
  }
@@ -5965,6 +6106,9 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
5965
6106
  // with the original receiver rather than a materialized property view.
5966
6107
  const callbackProperty = (() => {
5967
6108
  const prop = lowerer.checker.getPropertyOfType(recvTs, access.name.text);
6109
+ const mapped = lowerer.mapTypeOf(recvTs);
6110
+ 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)))
6111
+ return true;
5968
6112
  return prop !== undefined && lowerer.checker.declarationsOf(prop).some((decl) => ts.isPropertyDeclaration(decl) || ts.isPropertySignature(decl));
5969
6113
  })();
5970
6114
  const dispatched = callbackProperty ? null : lowerDynDispatchMethodCall(lowerer, call, access, recv, arrayReceiver);
@@ -6002,18 +6146,24 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
6002
6146
  type: DYN,
6003
6147
  loc: locOf(access),
6004
6148
  };
6149
+ const calleeLocal = lowerer.declareHiddenLocal("%dynCallCallee", DYN);
6150
+ const callee = varRef(calleeLocal.id, DYN, loc);
6151
+ const stmts = [
6152
+ { kind: "varDecl", localId: receiverLocal.id, init: recv, loc },
6153
+ { kind: "varDecl", localId: calleeLocal.id, init: member, loc },
6154
+ ];
6005
6155
  if (call.arguments.some(ts.isSpreadElement)) {
6006
- const spread = lowerSpreadArgsCall(lowerer, call, member, loc);
6156
+ const spread = lowerSpreadArgsCall(lowerer, call, callee, loc);
6007
6157
  if (spread?.kind === "dynCall")
6008
6158
  return { kind: "seqExpr",
6009
- stmts: [{ kind: "varDecl", localId: receiverLocal.id, init: recv, loc }],
6159
+ stmts,
6010
6160
  result: { ...spread, receiver }, type: DYN, loc };
6011
6161
  lowerer.unsupported("SC1090", call, "spread arguments in calls through 'unknown' values");
6012
6162
  }
6013
6163
  const args = call.arguments.map((a) => lowerer.lowerExprExpecting(a, DYN));
6014
6164
  return {
6015
- kind: "seqExpr", stmts: [{ kind: "varDecl", localId: receiverLocal.id, init: recv, loc }],
6016
- result: { kind: "dynCall", callee: member, receiver, calleeName: access.getText(), args, type: DYN, loc }, type: DYN, loc,
6165
+ kind: "seqExpr", stmts,
6166
+ result: { kind: "dynCall", callee, receiver, calleeName: access.getText(), args, type: DYN, loc }, type: DYN, loc,
6017
6167
  };
6018
6168
  }
6019
6169
  /** Prototype method names of the checked-dynamic tree-representable kinds (String, Array,
@@ -6041,6 +6191,7 @@ const DYN_PROTO_METHOD_NAMES = new Set([
6041
6191
  * is-not-a-function where the kind's prototype lacks the name, and
6042
6192
  * fences LOUDLY on real-but-unimplemented pairs. */
6043
6193
  const DYN_DISPATCH_METHODS = new Set([
6194
+ "toFixed", "toExponential",
6044
6195
  "segment", "containing", "resolvedOptions", "test", "exec",
6045
6196
  "apply", "bind", "call",
6046
6197
  "push", "pop", "shift", "unshift", "slice", "at",
@@ -6539,6 +6690,15 @@ function lowerPrimitiveProtoCall(lowerer, call, recv, name, memberSym) {
6539
6690
  if (!lowerer.isStdlibSymbol(memberSym))
6540
6691
  return null;
6541
6692
  const recvKind = lowerer.mapTypeOf(lowerer.typeOf(recv))?.kind;
6693
+ if ((name === "toFixed" || name === "toExponential") && call.arguments.length <= 1 &&
6694
+ !call.arguments.some(ts.isSpreadElement) && isJsSourceFile(call.getSourceFile())) {
6695
+ const operand = lowerer.lowerExpr(recv);
6696
+ if (operand.type.kind === "dyn" || operand.type.kind === "union" && lowerer.dynConvertible(operand.type))
6697
+ return {
6698
+ kind: "dynInvoke", recv: lowerer.coerceToExpected(operand, DYN), method: name, calleeName: `${recv.getText()}.${name}`,
6699
+ args: call.arguments.map((argument) => lowerer.lowerExprExpecting(argument, DYN)), type: DYN, loc: locOf(call),
6700
+ };
6701
+ }
6542
6702
  if (recvKind !== "f64" && recvKind !== "bool" && recvKind !== "string")
6543
6703
  return null;
6544
6704
  const loc = locOf(call);
@@ -7019,6 +7179,17 @@ export function lowerNestedFunctionDecl(lowerer, stmt) {
7019
7179
  throw new InternalCompilerError("lowerer bug: nested function declaration has no active statement list");
7020
7180
  }
7021
7181
  const init = lowerer.lowerLambda(stmt);
7182
+ // Body inference may settle a JS return differently from the initial
7183
+ // checker signature. Publish that same ABI on the hoisted binding and
7184
+ // every mutable capture of it before callers are lowered.
7185
+ if (init.type.kind === "func" && !typeEquals(local.type, init.type)) {
7186
+ local.type = init.type;
7187
+ for (const fn of lowerer.liftedFns)
7188
+ for (const capture of fn.captures ?? []) {
7189
+ if (capture.localId === local.id)
7190
+ capture.type = init.type;
7191
+ }
7192
+ }
7022
7193
  return { kind: "assign", localId: local.id, value: init, loc: locOf(stmt) };
7023
7194
  }
7024
7195
  /** Signature checks + param shapes + IR func type for any lambda-like
@@ -7183,6 +7354,13 @@ export function lowerLambda(lowerer, node) {
7183
7354
  const signature = lowerer.lambdaSignature(node);
7184
7355
  const { shapes } = signature;
7185
7356
  let { funcType } = signature;
7357
+ // Reflected JS methods receive the caller's actual `this`, which may
7358
+ // be a Proxy or a descriptor-created object rather than the class.
7359
+ // Fluent methods must return that receiver without a class cast.
7360
+ if (ts.isMethodDeclaration(node) && isJsSourceFile(node.getSourceFile()) &&
7361
+ !node.type && !node.asteriskToken && !hasExplicitJsDocReturn(node) && returnsOnlyThis(node)) {
7362
+ funcType = { ...funcType, ret: funcType.ret.kind === "promise" ? { ...funcType.ret, inner: DYN } : DYN };
7363
+ }
7186
7364
  // A lambda IS a value: the completed-ABI rule applies at birth. The
7187
7365
  // contextual (target) type decides — `(x?: number) => void` may flow
7188
7366
  // into a slot annotated `(x: number | undefined) => void` (same ABI
@@ -7792,7 +7970,7 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
7792
7970
  value: {
7793
7971
  kind: "dynCall",
7794
7972
  callee: { kind: "varRef", localId: cbLocal.id, type: DYN, loc },
7795
- calleeName: jsFuncNameOf(call.arguments[0]) ?? "onFulfilled",
7973
+ calleeName: jsFuncNameOf(call.arguments[0], lowerer) ?? "onFulfilled",
7796
7974
  args: handlerArgs,
7797
7975
  type: DYN,
7798
7976
  loc,
@@ -7825,7 +8003,8 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
7825
8003
  lowerer.unsupported("SC1090", call.arguments[0], "then handlers with more than one parameter (the two-argument onRejected form has no lowering — chain .catch(...) instead)");
7826
8004
  }
7827
8005
  const param = cb.type.params[0];
7828
- if (param !== undefined && !typeEquals(param, inner) && !(inner.kind === "void" && param.kind === "dyn")) {
8006
+ if (param !== undefined && !typeEquals(param, inner) &&
8007
+ !(param.kind === "dyn" && (inner.kind === "void" || lowerer.dynConvertible(inner)))) {
7829
8008
  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)}')`);
7830
8009
  }
7831
8010
  const resultT = lowerer.mapTypeOf(lowerer.typeOf(call));
@@ -7855,7 +8034,7 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
7855
8034
  if (param !== undefined && inner.kind !== "void") {
7856
8035
  const vLocal = lowerer.declareHiddenLocal("v", inner);
7857
8036
  body.push({ kind: "varDecl", localId: vLocal.id, init: awaitE, loc });
7858
- handlerArgs = [{ kind: "varRef", localId: vLocal.id, type: inner, loc }];
8037
+ handlerArgs = [lowerer.coerceToExpected({ kind: "varRef", localId: vLocal.id, type: inner, loc }, param)];
7859
8038
  }
7860
8039
  else {
7861
8040
  body.push({ kind: "exprStmt", expr: awaitE, loc });
@@ -7916,6 +8095,14 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
7916
8095
  }
7917
8096
  if (member === "finally") {
7918
8097
  const cb = lowerer.lowerExpr(call.arguments[0]);
8098
+ if (lowerer.dynConvertible(promT) && lowerer.dynConvertible(cb.type)) {
8099
+ const result = {
8100
+ kind: "dynInvoke", recv: lowerer.coerceToExpected(receiver, DYN),
8101
+ method: "finally", calleeName: access.getText(),
8102
+ args: [lowerer.coerceToExpected(cb, DYN)], type: DYN, loc,
8103
+ };
8104
+ return lowerer.coerceToExpected(result, promT);
8105
+ }
7919
8106
  if (cb.type.kind !== "func" || cb.type.params.length !== 0 || cb.type.ret.kind !== "void") {
7920
8107
  lowerer.unsupported("SC1090", call.arguments[0], "finally callbacks with parameters or a return value (use () => { ... })");
7921
8108
  }
@@ -7992,7 +8179,8 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
7992
8179
  // receiver, passes fulfillments through as dyn, and on rejection
7993
8180
  // calls the boxed handler with caughtToDyn's identity-preserving
7994
8181
  // snapshot (the dyn-then desugar's catch twin).
7995
- if (member === "catch" && inner.kind === "dyn") {
8182
+ if (member === "catch" && (inner.kind === "dyn" || isJsSourceFile(call.getSourceFile()) &&
8183
+ (inner.kind === "void" || lowerer.dynConvertible(inner)))) {
7996
8184
  let cb = lowerer.lowerExpr(call.arguments[0]);
7997
8185
  if (cb.type.kind === "func" &&
7998
8186
  canBoxFuncIntoDyn(cb.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
@@ -8009,20 +8197,11 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
8009
8197
  const pLocal = lowerer.declareHiddenLocal("p", promT);
8010
8198
  const cbLocal = lowerer.declareHiddenLocal("cb", DYN);
8011
8199
  const eLocal = lowerer.declareHiddenLocal("e", CAUGHT);
8012
- const vLocal = lowerer.declareHiddenLocal("v", DYN);
8200
+ const vLocal = inner.kind === "void" ? null : lowerer.declareHiddenLocal("v", inner);
8201
+ const awaited = { kind: "awaitExpr", value: { kind: "varRef", localId: pLocal.id, type: promT, loc }, type: inner, loc };
8013
8202
  const tryBody = [
8014
- {
8015
- kind: "varDecl",
8016
- localId: vLocal.id,
8017
- init: {
8018
- kind: "awaitExpr",
8019
- value: { kind: "varRef", localId: pLocal.id, type: promT, loc },
8020
- type: DYN,
8021
- loc,
8022
- },
8023
- loc,
8024
- },
8025
- { kind: "return", value: { kind: "varRef", localId: vLocal.id, type: DYN, loc }, loc },
8203
+ vLocal ? { kind: "varDecl", localId: vLocal.id, init: awaited, loc } : { kind: "exprStmt", expr: awaited, loc },
8204
+ { kind: "return", value: vLocal ? lowerer.coerceToExpected(varRef(vLocal.id, inner, loc), DYN) : dynUndefinedExpr(loc), loc },
8026
8205
  ];
8027
8206
  const catchBody = [
8028
8207
  {
@@ -8030,7 +8209,7 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
8030
8209
  value: {
8031
8210
  kind: "dynCall",
8032
8211
  callee: { kind: "varRef", localId: cbLocal.id, type: DYN, loc },
8033
- calleeName: jsFuncNameOf(call.arguments[0]) ?? "onRejected",
8212
+ calleeName: jsFuncNameOf(call.arguments[0], lowerer) ?? "onRejected",
8034
8213
  args: [
8035
8214
  {
8036
8215
  kind: "caughtToDyn",
@@ -8833,7 +9012,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
8833
9012
  !call.arguments.some(ts.isSpreadElement) && !lowerer.dynamic) {
8834
9013
  let object = lowerer.lowerExpr(call.arguments[0]);
8835
9014
  if (object.type.kind === "func") {
8836
- const fnName = jsFuncNameOf(call.arguments[0]);
9015
+ const fnName = jsFuncNameOf(call.arguments[0], lowerer);
8837
9016
  object = { kind: "dynFrom", value: object, type: DYN, loc: locOf(call),
8838
9017
  ...(fnName !== null ? { fnName } : {}) };
8839
9018
  }
@@ -8841,8 +9020,15 @@ function lowerObjectStaticCall(lowerer, call, access) {
8841
9020
  object = lowerer.coerceInto(call.arguments[0], object, DYN);
8842
9021
  if (object.type.kind === "dyn") {
8843
9022
  const loc = locOf(call);
8844
- if (member === "getPrototypeOf")
8845
- return { kind: "libCall", fn: "dyn.getPrototype", args: [object], type: DYN, loc };
9023
+ if (member === "getPrototypeOf") {
9024
+ let parent = call.parent;
9025
+ while (parent && ts.isParenthesizedExpression(parent))
9026
+ parent = parent.parent;
9027
+ const identityOnly = !!parent && ts.isBinaryExpression(parent) &&
9028
+ [ts.SyntaxKind.EqualsEqualsEqualsToken, ts.SyntaxKind.ExclamationEqualsEqualsToken].includes(parent.operatorToken.kind);
9029
+ return { kind: "libCall", fn: "dyn.getPrototype", args: [object], type: DYN, loc,
9030
+ ...(identityOnly ? { prototypeIdentityOnly: true } : {}) };
9031
+ }
8846
9032
  const prototype = lowerer.lowerExprExpecting(call.arguments[1], DYN);
8847
9033
  if (prototype.type.kind === "dyn")
8848
9034
  return { kind: "libCall", fn: "dyn.setPrototype", args: [object, prototype], type: DYN, loc };
@@ -9024,7 +9210,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
9024
9210
  if (isJsSourceFile(call.getSourceFile()) && call.arguments.length > 0 && !call.arguments.some(ts.isSpreadElement)) {
9025
9211
  const target = tryLowerExpression(lowerer, call.arguments[0]);
9026
9212
  if (target && ((target.type.kind === "func" && lowerer.dynConvertible(target.type)) ||
9027
- (target.type.kind === "object" && lowerer.errorHierarchyClassOf(target.type.className)))) {
9213
+ (target.type.kind === "object" && lowerer.dynConvertible(target.type)))) {
9028
9214
  const loc = locOf(call);
9029
9215
  return { kind: "libCall", fn: "dyn.assignAll", args: [lowerer.coerceToExpected(target, DYN),
9030
9216
  { kind: "dynArrLit", elems: call.arguments.slice(1).map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc },
@@ -9226,7 +9412,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
9226
9412
  target = lowerer.coerceToExpected(target, DYN);
9227
9413
  }
9228
9414
  if (target?.type.kind === "func" && lowerer.dynConvertible(target.type)) {
9229
- const fnName = jsFuncNameOf(call.arguments[0]);
9415
+ const fnName = jsFuncNameOf(call.arguments[0], lowerer);
9230
9416
  target = { kind: "dynFrom", value: target, type: DYN, loc: locOf(call.arguments[0]), ...(fnName !== null ? { fnName } : {}) };
9231
9417
  }
9232
9418
  const descriptorPrimitive = member === "getOwnPropertyDescriptor" && target &&
@@ -9255,6 +9441,9 @@ function lowerObjectStaticCall(lowerer, call, access) {
9255
9441
  // static shapes have no property table to extend.
9256
9442
  if (member === "defineProperties" && call.arguments.length === 2 &&
9257
9443
  !call.arguments.some((a) => ts.isSpreadElement(a))) {
9444
+ const prototype = lowerClassPrototypeDescriptors(lowerer, call, member);
9445
+ if (prototype)
9446
+ return prototype;
9258
9447
  let target = tryLowerExpression(lowerer, call.arguments[0]);
9259
9448
  if (target) {
9260
9449
  const native = lowerClassDataDescriptor(lowerer, call, member, target);
@@ -9267,7 +9456,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
9267
9456
  // wrapper returned later reads the same table.
9268
9457
  if (target && target.type.kind === "func" &&
9269
9458
  canBoxFuncIntoDyn(target.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
9270
- const fnName = jsFuncNameOf(call.arguments[0]);
9459
+ const fnName = jsFuncNameOf(call.arguments[0], lowerer);
9271
9460
  target = { kind: "dynFrom", value: target, type: DYN, loc: locOf(call.arguments[0]), ...(fnName !== null ? { fnName } : {}) };
9272
9461
  }
9273
9462
  if (target && isUnitType(target.type)) {
@@ -9322,7 +9511,8 @@ function lowerObjectStaticCall(lowerer, call, access) {
9322
9511
  let inner = argNode;
9323
9512
  while (ts.isParenthesizedExpression(inner) || ts.isAsExpression(inner))
9324
9513
  inner = inner.expression;
9325
- const value = lowerer.lowerExpr(argNode);
9514
+ const value = isJsSourceFile(call.getSourceFile()) && (ts.isObjectLiteralExpression(inner) || ts.isArrayLiteralExpression(inner))
9515
+ ? lowerer.lowerExprExpecting(argNode, DYN) : lowerer.lowerExpr(argNode);
9326
9516
  if (value.type.kind === "dyn")
9327
9517
  return { kind: "libCall", fn: "dyn.freeze", args: [value], type: DYN, loc: locOf(call) };
9328
9518
  if (ts.isObjectLiteralExpression(inner) || ts.isArrayLiteralExpression(inner)) {
@@ -9458,14 +9648,11 @@ function lowerObjectStaticCall(lowerer, call, access) {
9458
9648
  }
9459
9649
  }
9460
9650
  let argIr = lowerer.mapTypeOf(lowerer.typeOf(argNode));
9461
- // JS: an unmappable CHECKER type over a value that lowered to a real
9462
- // record (the narrowed export-table literal) — the lowered value's
9463
- // shape is the honest dispatch key, exactly the identity-Set stance.
9464
- if (argIr === null && isJsSourceFile(argNode.getSourceFile())) {
9465
- const probed = tryLowerExpression(lowerer, argNode);
9466
- if (probed?.type.kind === "record")
9467
- argIr = probed.type;
9468
- }
9651
+ // Inferred records can carry runtime-optional index values that the
9652
+ // checker omits (named regex captures). Enumerate the represented shape.
9653
+ const represented = tryLowerExpression(lowerer, argNode);
9654
+ if (represented?.type.kind === "record")
9655
+ argIr = represented.type;
9469
9656
  if (argIr?.kind !== "record")
9470
9657
  return null; // Maps, classes, arrays → the SC2020 fence
9471
9658
  const shape = lowerer.shapes.get(argIr.shapeId);
@@ -9857,6 +10044,13 @@ export function lowerRecordFieldCall(lowerer, call, access) {
9857
10044
  return { kind: "callValue", callee, args, type: callee.type.ret, loc: locOf(call) };
9858
10045
  }
9859
10046
  const target = lowerer.fieldTarget(access);
10047
+ const loc = locOf(call);
10048
+ const receiverLocal = target && isJsSourceFile(call.getSourceFile())
10049
+ ? lowerer.declareHiddenLocal("%callReceiver", target.obj.type) : null;
10050
+ const init = target && receiverLocal
10051
+ ? { kind: "varDecl", localId: receiverLocal.id, init: target.obj, loc } : null;
10052
+ if (target && receiverLocal)
10053
+ target.obj = varRef(receiverLocal.id, receiverLocal.type, loc);
9860
10054
  let callee = target ? lowerer.fieldGetExpr(target, locOf(access), access) : null;
9861
10055
  if (!callee)
9862
10056
  return null;
@@ -9865,10 +10059,24 @@ export function lowerRecordFieldCall(lowerer, call, access) {
9865
10059
  // `.bold` (the chalk shape).
9866
10060
  if (callee.type.kind === "record")
9867
10061
  callee = lowerer.hybridCallUnwrap(callee);
10062
+ // Inferred JavaScript option records can retain checked callables in
10063
+ // fields even when the checker only describes those members as any.
10064
+ if (callee.type.kind === "dyn" && isJsSourceFile(call.getSourceFile())) {
10065
+ const receiver = target && receiverLocal ? lowerer.coerceToExpected(target.obj, DYN) : undefined;
10066
+ const spread = call.arguments.some(ts.isSpreadElement) ? lowerSpreadArgsCall(lowerer, call, callee, loc) : null;
10067
+ if (spread && spread.kind !== "dynCall")
10068
+ lowerer.unsupported("SC1090", call, "checked record property call spread arguments");
10069
+ const result = spread ? (receiver ? { ...spread, receiver } : spread) : {
10070
+ kind: "dynCall", callee, ...(receiver ? { receiver } : {}), calleeName: access.getText(),
10071
+ args: call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc,
10072
+ };
10073
+ return init ? { kind: "seqExpr", stmts: [init], result, type: result.type, loc } : result;
10074
+ }
9868
10075
  if (callee.type.kind !== "func")
9869
10076
  lowerer.badType(access, lowerer.typeOf(access));
9870
10077
  const args = completeFuncValueArgs(lowerer, call, callee.type, locOf(call));
9871
- return { kind: "callValue", callee, args, type: callee.type.ret, loc: locOf(call) };
10078
+ const result = { kind: "callValue", callee, ...(target && receiverLocal ? { receiver: lowerer.coerceToExpected(target.obj, DYN) } : {}), args, type: callee.type.ret, loc };
10079
+ return init ? { kind: "seqExpr", stmts: [init], result, type: result.type, loc } : result;
9872
10080
  }
9873
10081
  /** The function-like node behind an object-literal generic-method member:
9874
10082
  * the MethodDeclaration itself (`{ m<T>(x: T) {...} }`) or a generic
@@ -10526,7 +10734,8 @@ export function requireObjLitGenericReceiver(lowerer, blame, recvExpr, literal,
10526
10734
  * direct `call` of the instance with the receiver unevaluated. Claims
10527
10735
  * every call whose member is generic-callable — lowering it or fencing
10528
10736
  * with a named message. */
10529
- /** URL.revokeObjectURL() with NO argument: Node's ERR_MISSING_ARGS
10737
+ /** The URL factories use the constructor's conversion order and parser.
10738
+ * URL.revokeObjectURL() with NO argument: Node's ERR_MISSING_ARGS
10530
10739
  * throws before the registry lookup, so the zero-argument contract is
10531
10740
  * exact without any blob machinery. The one-argument form (Node's
10532
10741
  * silent no-op for unregistered ids) and createObjectURL keep their
@@ -10534,12 +10743,15 @@ export function requireObjLitGenericReceiver(lowerer, blame, recvExpr, literal,
10534
10743
  function lowerUrlStaticCall(lowerer, call, callee) {
10535
10744
  if (!ts.isPropertyAccessExpression(callee) || callee.questionDotToken !== undefined)
10536
10745
  return null;
10537
- if (!ts.isIdentifier(callee.expression) || callee.expression.text !== "URL")
10538
- return null;
10539
- if (callee.name.text !== "revokeObjectURL" || call.arguments.length !== 0)
10746
+ if (!ts.isIdentifier(callee.expression))
10540
10747
  return null;
10541
10748
  const sym = lowerer.resolveValueSymbol(callee.expression);
10542
- if (!sym || !lowerer.isStdlibSymbol(sym))
10749
+ if (!sym || !lowerer.isStdlibSymbol(sym) || sym.name !== "URL")
10750
+ return null;
10751
+ if (callee.name.text === "canParse" || callee.name.text === "parse") {
10752
+ return lowerUrlFactory(lowerer, call, callee.name.text);
10753
+ }
10754
+ if (callee.name.text !== "revokeObjectURL" || call.arguments.length !== 0)
10543
10755
  return null;
10544
10756
  return nodeThrowExpr(1, "ERR_MISSING_ARGS", 'The "url" argument must be specified', VOID, locOf(call));
10545
10757
  }
@@ -10820,9 +11032,11 @@ export function lowerObjectMethodCall(lowerer, call, access) {
10820
11032
  // type still belongs to the unspecialized body (plane.normal.dot()).
10821
11033
  // Use the lowered receiver's representation and retain its evaluation.
10822
11034
  const probe = mappedReceiver?.kind !== "object" && (lowerer.implicitParamTypes !== null || ts.isNewExpression(access.expression) ||
10823
- isJsSourceFile(call.getSourceFile()) && ts.isCallExpression(access.expression))
10824
- ? tryLowerExpression(lowerer, access.expression) : null;
10825
- const specializedReceiver = probe?.type.kind === "object" ? probe : null;
11035
+ isJsSourceFile(call.getSourceFile()))
11036
+ ? ts.isNewExpression(access.expression) ? lowerer.lowerExpr(access.expression) : tryLowerExpression(lowerer, access.expression)
11037
+ : null;
11038
+ const specializedReceiver = probe?.type.kind === "object" || probe?.type.kind === "union" &&
11039
+ lowerer.unions.get(probe.type.unionId)?.arms.some((arm) => arm.kind === "object") ? probe : null;
10826
11040
  if (specializedReceiver)
10827
11041
  mappedReceiver = specializedReceiver.type;
10828
11042
  if (mappedReceiver?.kind === "union") {
@@ -10833,8 +11047,7 @@ export function lowerObjectMethodCall(lowerer, call, access) {
10833
11047
  const arms = lowerer.unions.get(mappedReceiver.unionId)?.arms;
10834
11048
  if (isJsSourceFile(call.getSourceFile()) && arms?.every((arm) => arm.kind === "object" &&
10835
11049
  !lowerer.classes.get(arm.className)?.def.runtime) && lowerer.dynConvertible(mappedReceiver)) {
10836
- const receiver = lowerer.coerceInto(access.expression, lowerer.lowerExpr(access.expression), DYN);
10837
- return lowerDynDispatchMethodCall(lowerer, call, access, receiver, false);
11050
+ return lowerDynReceiverMethodCall(lowerer, call, access);
10838
11051
  }
10839
11052
  }
10840
11053
  const receiverIr = mappedReceiver?.kind === "object"
@@ -10982,7 +11195,7 @@ export function lowerObjectMethodCall(lowerer, call, access) {
10982
11195
  const fallback = virtual
10983
11196
  ? { kind: "virtualCall", className: info.def.name, method, args: [lowerer.upcastTo(value, info.def.name), ...args], type: found.sig.ret, loc }
10984
11197
  : { kind: "call", callee: `%${found.declarer.def.name}.${method}`, args: [lowerer.upcastTo(value, found.declarer.def.name), ...args], type: found.sig.ret, loc };
10985
- const result = classCallbackCall(lowerer, value, method, call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), fallback, loc);
11198
+ const result = classCallbackCall(lowerer, value, method, call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), fallback, loc, access.getText());
10986
11199
  return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id, init: receiver, loc }], result, type: result.type, loc };
10987
11200
  }
10988
11201
  if (found.declarer.builtinError) {