@scriptc/compiler 0.2.0 → 0.2.1

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 (194) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +25 -15
  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 +5 -0
  7. package/dist/backend/llvm/dyn.js +166 -99
  8. package/dist/backend/llvm/dyn.js.map +1 -1
  9. package/dist/backend/llvm/emitter.d.ts +2 -2
  10. package/dist/backend/llvm/emitter.js +79 -20
  11. package/dist/backend/llvm/emitter.js.map +1 -1
  12. package/dist/backend/llvm/expr-bytes.d.ts +1 -1
  13. package/dist/backend/llvm/expr-bytes.js +28 -17
  14. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  15. package/dist/backend/llvm/expr-control.js +1 -1
  16. package/dist/backend/llvm/expr-control.js.map +1 -1
  17. package/dist/backend/llvm/expr-dynamic.js +18 -9
  18. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  19. package/dist/backend/llvm/expr-primitives.js +11 -1
  20. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  21. package/dist/backend/llvm/expr-records.js +11 -3
  22. package/dist/backend/llvm/expr-records.js.map +1 -1
  23. package/dist/backend/llvm/expr-stream-bridges.js +125 -17
  24. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  25. package/dist/backend/llvm/lib-process.js +23 -3
  26. package/dist/backend/llvm/lib-process.js.map +1 -1
  27. package/dist/backend/llvm/lib-shared.js +45 -2
  28. package/dist/backend/llvm/lib-shared.js.map +1 -1
  29. package/dist/backend/llvm/shapes.js +8 -2
  30. package/dist/backend/llvm/shapes.js.map +1 -1
  31. package/dist/backend/native-toolchain.d.ts +3 -6
  32. package/dist/backend/native-toolchain.js +53 -23
  33. package/dist/backend/native-toolchain.js.map +1 -1
  34. package/dist/backend/native-toolchain.test.js +72 -0
  35. package/dist/backend/native-toolchain.test.js.map +1 -1
  36. package/dist/backend/runtime-abi.d.ts +2 -2
  37. package/dist/backend/runtime-abi.js +2 -2
  38. package/dist/backend/runtime-pack-native.js +4 -1
  39. package/dist/backend/runtime-pack-native.js.map +1 -1
  40. package/dist/backend/runtime-pack-targets.test.js +1 -1
  41. package/dist/backend/runtime-pack.test.js +1 -1
  42. package/dist/backend/targets.js +10 -6
  43. package/dist/backend/targets.js.map +1 -1
  44. package/dist/backend/targets.test.js +7 -0
  45. package/dist/backend/targets.test.js.map +1 -1
  46. package/dist/compat/fetch-profile.js +34 -4
  47. package/dist/compat/fetch-profile.js.map +1 -1
  48. package/dist/diagnostics/diagnostic.js +2 -7
  49. package/dist/diagnostics/diagnostic.js.map +1 -1
  50. package/dist/frontend/lowering/class-callbacks.d.ts +3 -3
  51. package/dist/frontend/lowering/class-callbacks.js +26 -15
  52. package/dist/frontend/lowering/class-callbacks.js.map +1 -1
  53. package/dist/frontend/lowering/class-construction.d.ts +12 -0
  54. package/dist/frontend/lowering/class-construction.js +156 -0
  55. package/dist/frontend/lowering/class-construction.js.map +1 -0
  56. package/dist/frontend/lowering/class-descriptors.d.ts +1 -0
  57. package/dist/frontend/lowering/class-descriptors.js +46 -5
  58. package/dist/frontend/lowering/class-descriptors.js.map +1 -1
  59. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +11 -1
  60. package/dist/frontend/lowering/class-dynamic-dispatch.js +403 -48
  61. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  62. package/dist/frontend/lowering/class-dynamic-dispatch.test.js +2 -1
  63. package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
  64. package/dist/frontend/lowering/class-instance-constructor.js +4 -1
  65. package/dist/frontend/lowering/class-instance-constructor.js.map +1 -1
  66. package/dist/frontend/lowering/class-method-values.d.ts +4 -1
  67. package/dist/frontend/lowering/class-method-values.js +72 -7
  68. package/dist/frontend/lowering/class-method-values.js.map +1 -1
  69. package/dist/frontend/lowering/class-prototypes.d.ts +5 -2
  70. package/dist/frontend/lowering/class-prototypes.js +121 -13
  71. package/dist/frontend/lowering/class-prototypes.js.map +1 -1
  72. package/dist/frontend/lowering/class-runtime-statics.d.ts +8 -0
  73. package/dist/frontend/lowering/class-runtime-statics.js +66 -0
  74. package/dist/frontend/lowering/class-runtime-statics.js.map +1 -0
  75. package/dist/frontend/lowering/class-static-data.js +2 -2
  76. package/dist/frontend/lowering/class-static-data.js.map +1 -1
  77. package/dist/frontend/lowering/containers/bytes.js +49 -13
  78. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  79. package/dist/frontend/lowering/containers/string-and-regexp.js +19 -47
  80. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  81. package/dist/frontend/lowering/error-methods.d.ts +4 -1
  82. package/dist/frontend/lowering/error-methods.js +100 -1
  83. package/dist/frontend/lowering/error-methods.js.map +1 -1
  84. package/dist/frontend/lowering/expressions/native-proxy.js +3 -1
  85. package/dist/frontend/lowering/expressions/native-proxy.js.map +1 -1
  86. package/dist/frontend/lowering/expressions/nullish-assignment.js +19 -11
  87. package/dist/frontend/lowering/expressions/nullish-assignment.js.map +1 -1
  88. package/dist/frontend/lowering/expressions/object-literals.js +38 -7
  89. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  90. package/dist/frontend/lowering/expressions/optional-chains.d.ts +3 -4
  91. package/dist/frontend/lowering/expressions/optional-chains.js +69 -17
  92. package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
  93. package/dist/frontend/lowering/function-context.d.ts +11 -3
  94. package/dist/frontend/lowering/function-context.js +11 -5
  95. package/dist/frontend/lowering/function-context.js.map +1 -1
  96. package/dist/frontend/lowering/generator-dynamic-dispatch.d.ts +1 -0
  97. package/dist/frontend/lowering/generator-dynamic-dispatch.js +39 -1
  98. package/dist/frontend/lowering/generator-dynamic-dispatch.js.map +1 -1
  99. package/dist/frontend/lowering/lib-boundary.d.ts +2 -0
  100. package/dist/frontend/lowering/lib-boundary.js +54 -1
  101. package/dist/frontend/lowering/lib-boundary.js.map +1 -1
  102. package/dist/frontend/lowering/lower-builtin-values.d.ts +7 -1
  103. package/dist/frontend/lowering/lower-builtin-values.js +113 -3
  104. package/dist/frontend/lowering/lower-builtin-values.js.map +1 -1
  105. package/dist/frontend/lowering/lower-builtins.d.ts +6 -5
  106. package/dist/frontend/lowering/lower-builtins.js +156 -41
  107. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  108. package/dist/frontend/lowering/lower-calls.d.ts +8 -5
  109. package/dist/frontend/lowering/lower-calls.js +448 -83
  110. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  111. package/dist/frontend/lowering/lower-classes.d.ts +13 -13
  112. package/dist/frontend/lowering/lower-classes.js +650 -176
  113. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  114. package/dist/frontend/lowering/lower-containers.d.ts +9 -0
  115. package/dist/frontend/lowering/lower-containers.js +135 -36
  116. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  117. package/dist/frontend/lowering/lower-dgram.js +3 -2
  118. package/dist/frontend/lowering/lower-dgram.js.map +1 -1
  119. package/dist/frontend/lowering/lower-exprs.d.ts +2 -2
  120. package/dist/frontend/lowering/lower-exprs.js +531 -126
  121. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  122. package/dist/frontend/lowering/lower-generators.js +12 -1
  123. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  124. package/dist/frontend/lowering/lower-island.d.ts +2 -0
  125. package/dist/frontend/lowering/lower-island.js +32 -10
  126. package/dist/frontend/lowering/lower-island.js.map +1 -1
  127. package/dist/frontend/lowering/lower-modules.js +220 -17
  128. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  129. package/dist/frontend/lowering/lower-modules.test.d.ts +1 -0
  130. package/dist/frontend/lowering/lower-modules.test.js +39 -0
  131. package/dist/frontend/lowering/lower-modules.test.js.map +1 -0
  132. package/dist/frontend/lowering/lower-stmts.d.ts +7 -3
  133. package/dist/frontend/lowering/lower-stmts.js +135 -26
  134. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  135. package/dist/frontend/lowering/lower-stream.js +1 -1
  136. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  137. package/dist/frontend/lowering/lowerer.d.ts +27 -1
  138. package/dist/frontend/lowering/lowerer.js +172 -50
  139. package/dist/frontend/lowering/lowerer.js.map +1 -1
  140. package/dist/frontend/lowering/lowerer.test.js +149 -3
  141. package/dist/frontend/lowering/lowerer.test.js.map +1 -1
  142. package/dist/frontend/lowering/surfaces.d.ts +2 -0
  143. package/dist/frontend/lowering/surfaces.js +25 -8
  144. package/dist/frontend/lowering/surfaces.js.map +1 -1
  145. package/dist/frontend/lowering/text-decoder-encoding.d.ts +2 -0
  146. package/dist/frontend/lowering/text-decoder-encoding.js +5 -0
  147. package/dist/frontend/lowering/text-decoder-encoding.js.map +1 -1
  148. package/dist/frontend/lowering/unregistered-class-types.test.js +3 -3
  149. package/dist/frontend/lowering/unregistered-class-types.test.js.map +1 -1
  150. package/dist/frontend/npm-static-prune.js +116 -34
  151. package/dist/frontend/npm-static-prune.js.map +1 -1
  152. package/dist/frontend/npm-static-prune.test.js +8 -0
  153. package/dist/frontend/npm-static-prune.test.js.map +1 -1
  154. package/dist/frontend/program.d.ts +1 -1
  155. package/dist/frontend/program.js +53 -24
  156. package/dist/frontend/program.js.map +1 -1
  157. package/dist/frontend/program.test.js +18 -0
  158. package/dist/frontend/program.test.js.map +1 -1
  159. package/dist/frontend/ts7/ast.js +4 -3
  160. package/dist/frontend/ts7/ast.js.map +1 -1
  161. package/dist/frontend/ts7/semantic-json.js +5 -10
  162. package/dist/frontend/ts7/semantic-json.js.map +1 -1
  163. package/dist/frontend/type-mapper.d.ts +9 -1
  164. package/dist/frontend/type-mapper.js +90 -13
  165. package/dist/frontend/type-mapper.js.map +1 -1
  166. package/dist/frontend/type-mapper.test.js +23 -0
  167. package/dist/frontend/type-mapper.test.js.map +1 -1
  168. package/dist/frontend/union-discriminants.d.ts +1 -1
  169. package/dist/frontend/union-discriminants.js +2 -2
  170. package/dist/frontend/union-discriminants.js.map +1 -1
  171. package/dist/ir/analysis.js +2 -0
  172. package/dist/ir/analysis.js.map +1 -1
  173. package/dist/ir/ir.d.ts +52 -33
  174. package/dist/ir/ir.js +142 -42
  175. package/dist/ir/ir.js.map +1 -1
  176. package/dist/ir/ir.test.js +35 -0
  177. package/dist/ir/ir.test.js.map +1 -1
  178. package/dist/ir/serialize.js +15 -3
  179. package/dist/ir/serialize.js.map +1 -1
  180. package/dist/ir/serialize.test.js +5 -1
  181. package/dist/ir/serialize.test.js.map +1 -1
  182. package/dist/ir/validate.js +80 -11
  183. package/dist/ir/validate.js.map +1 -1
  184. package/dist/ir/validate.test.js +61 -1
  185. package/dist/ir/validate.test.js.map +1 -1
  186. package/dist/native/sanitizer.js +3 -1
  187. package/dist/native/sanitizer.js.map +1 -1
  188. package/dist/native/toolchain.d.ts +1 -1
  189. package/dist/native/toolchain.js +26 -6
  190. package/dist/native/toolchain.js.map +1 -1
  191. package/dist/native/toolchain.test.js +53 -1
  192. package/dist/native/toolchain.test.js.map +1 -1
  193. package/package.json +20 -20
  194. package/surface-manifest.json +56 -81
@@ -14,20 +14,21 @@ import { lowerClassPrototypeAssign } 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,7 @@ 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";
46
48
  export { bodyReadsArguments };
47
49
  /** The one func-type projection of completed parameter shapes. Typed rest
48
50
  * parameters keep their packed array as the trailing native ABI slot and
@@ -123,7 +125,21 @@ export const MAX_GENERIC_INSTANCES = 100;
123
125
  * - `...xs: T[]`: the ABI type is the array; call sites pack the surplus.
124
126
  */
125
127
  export function paramShape(lowerer, param) {
128
+ if (param.initializer && isJsSourceFile(param.getSourceFile()) && !param.type &&
129
+ !/@(?:param|type)\b/.test(param.getSourceFile().text.slice(param.parent?.pos ?? param.pos, param.getStart()))) {
130
+ return { type: DYN, mode: "omittable", bodyType: DYN };
131
+ }
132
+ // Inferred JS array patterns describe the bindings, not an exact tuple
133
+ // contract. Consume the actual iterable, including surplus elements.
134
+ if (ts.isArrayBindingPattern(param.name) && isJsSourceFile(param.getSourceFile()) && !param.type &&
135
+ !/@(?:param|type)\b/.test(param.getSourceFile().text.slice(param.parent?.pos ?? param.pos, param.getStart()))) {
136
+ if (param.dotDotDotToken)
137
+ return { type: DYN, mode: "dynRest" };
138
+ return param.initializer ? { type: DYN, mode: "omittable", bodyType: DYN } : { type: DYN, mode: "required" };
139
+ }
126
140
  if (lowerer.checkedCallbackParams.has(param)) {
141
+ if (param.dotDotDotToken)
142
+ return { type: DYN, mode: "dynRest" };
127
143
  return param.initializer
128
144
  ? { type: DYN, mode: "omittable", bodyType: DYN }
129
145
  : { type: DYN, mode: "required" };
@@ -207,7 +223,7 @@ export function paramShape(lowerer, param) {
207
223
  }
208
224
  const type = lowerer.runtimeOptionalBindingType(param.name, lowerer.irTypeOf(param.name));
209
225
  if (type.kind === "void") {
210
- lowerer.unsupported("SC1090", param, "function parameters with void type");
226
+ return { type: DYN, mode: param.questionToken ? "omittable" : "required" };
211
227
  }
212
228
  if (param.questionToken && !lowerer.bareUndefinedArmedUnion(type) && type.kind !== "dyn" && type.kind !== "jsval") {
213
229
  // `x?: unknown` where unknown came from an annotation: undefined is
@@ -624,8 +640,7 @@ leading) {
624
640
  lowerer.unsupported("SC1090", a, "spread arguments into fixed parameter positions (a spread can only fill a rest parameter)");
625
641
  }
626
642
  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") {
643
+ if (!isSafeToDiscard(v)) {
629
644
  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
645
  }
631
646
  }
@@ -856,7 +871,7 @@ export function appendImplicitUndefinedReturn(lowerer, body, bodyReturn, loc) {
856
871
  /** A declaration's checker-derived IR return type. The unmappable-type
857
872
  * diagnostic points at `blame` (the name for top-level declarations, the
858
873
  * whole node for lambda-likes — preserving each caller's historical loc). */
859
- function hasExplicitJsDocReturn(decl) {
874
+ export function hasExplicitJsDocReturn(decl) {
860
875
  const sourceFile = decl.getSourceFile();
861
876
  return /@returns?\b/.test(sourceFile.text.slice(decl.pos, decl.getStart(sourceFile)));
862
877
  }
@@ -866,6 +881,16 @@ function promiseCarriesDyn(lowerer, type) {
866
881
  return type.kind === "union" &&
867
882
  (lowerer.unions.get(type.unionId)?.arms.some((arm) => promiseCarriesDyn(lowerer, arm)) ?? false);
868
883
  }
884
+ function producesConstructor(lowerer, type) {
885
+ let result = type;
886
+ for (let depth = 0; result && depth < 8; depth++) {
887
+ if (lowerer.checker.getConstructSignatures(result).length > 0)
888
+ return true;
889
+ const signatures = lowerer.checker.getCallSignatures(result);
890
+ result = signatures.length === 1 ? lowerer.checker.getReturnTypeOfSignature(signatures[0]) : undefined;
891
+ }
892
+ return false;
893
+ }
869
894
  export function declaredReturnType(lowerer, decl, blame) {
870
895
  const sig = lowerer.checker.getSignatureFromDeclaration(decl);
871
896
  if (!sig)
@@ -882,6 +907,8 @@ export function declaredReturnType(lowerer, decl, blame) {
882
907
  if (retTsType.flags & ts.TypeFlags.Never)
883
908
  return VOID;
884
909
  const mappedReturn = lowerer.mapTypeOf(retTsType);
910
+ if (isJsSourceFile(decl.getSourceFile()) && mappedReturn?.kind === "array" && mappedReturn.elem.kind === "f64")
911
+ return DYN;
885
912
  if (isJsSourceFile(decl.getSourceFile()) && !decl.type && !hasExplicitJsDocReturn(decl) && mappedReturn?.kind === "date")
886
913
  return DYN;
887
914
  // JS inference assigns Number to arithmetic over any, although the
@@ -945,9 +972,12 @@ export function declaredReturnType(lowerer, decl, blame) {
945
972
  // that boundary; their factories keep the native record ABI.
946
973
  const asyncReturn = decl.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword) && mappedReturn?.kind === "promise";
947
974
  const recordReturn = asyncReturn ? mappedReturn.inner : mappedReturn;
975
+ const recordArms = recordReturn?.kind === "union" ? lowerer.unions.get(recordReturn.unionId)?.arms : recordReturn ? [recordReturn] : undefined;
976
+ const inferredRecordReturn = recordArms?.some((arm) => arm.kind === "record" || arm.kind === "object") &&
977
+ recordArms.every((arm) => isUnitType(arm) || arm.kind === "record" || arm.kind === "object" && !hasExplicitJsDocReturn(decl));
948
978
  if (isJsSourceFile(decl.getSourceFile()) &&
949
979
  decl.type === undefined &&
950
- recordReturn?.kind === "record" &&
980
+ recordReturn !== null && recordReturn !== undefined && inferredRecordReturn &&
951
981
  lowerer.dynConvertible(recordReturn) &&
952
982
  decl.parameters.every((p) => {
953
983
  const mt = lowerer.mapTypeOf(lowerer.typeOf(p));
@@ -1565,6 +1595,7 @@ export function lowerGenericInstance(lowerer, info, inst) {
1565
1595
  body.push(...lowerer.lowerStmts(bodyBlock.statements));
1566
1596
  if (fnCtx.inferReturn) {
1567
1597
  bodyReturn = resolveInferredReturn(lowerer, inst, fnCtx.inferReturn, body, decl);
1598
+ inst.returnType = bodyReturn;
1568
1599
  }
1569
1600
  appendImplicitUndefinedReturn(lowerer, body, bodyReturn, locOf(decl));
1570
1601
  }
@@ -1578,6 +1609,7 @@ export function lowerGenericInstance(lowerer, info, inst) {
1578
1609
  if (value.type.kind === "void") {
1579
1610
  body.push({ kind: "exprStmt", expr: value, loc: locOf(decl.body) });
1580
1611
  bodyReturn = resolveInferredReturn(lowerer, inst, fnCtx.inferReturn, body, decl);
1612
+ inst.returnType = bodyReturn;
1581
1613
  appendImplicitUndefinedReturn(lowerer, body, bodyReturn, locOf(decl));
1582
1614
  }
1583
1615
  else {
@@ -1585,6 +1617,7 @@ export function lowerGenericInstance(lowerer, info, inst) {
1585
1617
  fnCtx.inferReturn.entries.push({ stmt, node: decl.body });
1586
1618
  body.push(stmt);
1587
1619
  bodyReturn = resolveInferredReturn(lowerer, inst, fnCtx.inferReturn, body, decl);
1620
+ inst.returnType = bodyReturn;
1588
1621
  }
1589
1622
  }
1590
1623
  else {
@@ -1639,7 +1672,9 @@ export function lowerGenericInstance(lowerer, info, inst) {
1639
1672
  * adds JS's undefined; DYN when returns disagree (the checked-dynamic
1640
1673
  * result slot — today's shape). Same-key recursion PINNED the fallback
1641
1674
  * type mid-lowering (callers already hold it), so a pinned instance
1642
- * keeps it and the wrap pass coerces every return to the pin. */
1675
+ * keeps it and the wrap pass coerces every return to the pin. Callers
1676
+ * store the settled type on their full instance; this narrower view
1677
+ * can be a structural copy in native builds. */
1643
1678
  function resolveInferredReturn(lowerer, inst, infer, body, decl) {
1644
1679
  // The conservative completion test appendImplicitUndefinedReturn uses:
1645
1680
  // a body whose last statement isn't a terminator may complete without
@@ -1670,14 +1705,13 @@ function resolveInferredReturn(lowerer, inst, infer, body, decl) {
1670
1705
  else {
1671
1706
  final = DYN; // disagreeing returns: the checked-dynamic join
1672
1707
  }
1673
- inst.returnType = final;
1674
1708
  }
1675
1709
  // The wrap pass: settle every recorded return onto `final`, in place.
1710
+ // Write through the stored union arm: optional-field widening on a
1711
+ // local alias can otherwise introduce a record copy in native builds.
1676
1712
  for (const e of infer.entries) {
1677
1713
  if (e.stmt.kind !== "return")
1678
1714
  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
1715
  const diagsBefore = lowerer.diags.length;
1682
1716
  try {
1683
1717
  if (e.stmt.value === null || e.stmt.value === undefined) {
@@ -2076,6 +2110,33 @@ function implicitDeclaredReturn(lowerer, info) {
2076
2110
  return null;
2077
2111
  }
2078
2112
  const mapped = lowerer.mapTypeOf(retTs);
2113
+ if (mapped?.kind === "symbol" && !hasExplicitJsDocReturn(info.decl))
2114
+ return null;
2115
+ if (mapped?.kind === "date" && !hasExplicitJsDocReturn(info.decl))
2116
+ return DYN;
2117
+ if (!hasExplicitJsDocReturn(info.decl) && info.decl.body) {
2118
+ let openReturn = false;
2119
+ ts.walkPreorder(info.decl.body, (node) => {
2120
+ if (node !== info.decl.body && ts.isFunctionLike(node))
2121
+ return "skip";
2122
+ if (!ts.isReturnStatement(node) || !node.expression || !ts.isIdentifier(node.expression))
2123
+ return undefined;
2124
+ const symbol = lowerer.resolveValueSymbol(node.expression);
2125
+ if (symbol && lowerer.checker.declarationsOf(symbol).some((decl) => ts.isVariableDeclaration(decl) && jsBindingHasOpenWrites(lowerer, decl)))
2126
+ openReturn = true;
2127
+ return undefined;
2128
+ });
2129
+ if (openReturn)
2130
+ return null;
2131
+ }
2132
+ // A JavaScript result inferred from an initial record can later
2133
+ // carry additional fields. Settle its representation from the
2134
+ // lowered returns instead of copying it back into that initial shape.
2135
+ const resultArms = mapped?.kind === "union" ? lowerer.unions.get(mapped.unionId)?.arms : mapped ? [mapped] : [];
2136
+ if (resultArms?.some((arm) => arm.kind === "record" || arm.kind === "object" || arm.kind === "classval") &&
2137
+ resultArms.every((arm) => isUnitType(arm) || arm.kind === "record" || arm.kind === "object" || arm.kind === "classval") &&
2138
+ !hasExplicitJsDocReturn(info.decl))
2139
+ return null;
2079
2140
  // Inferred variadic results carry runtime argument packs. Their
2080
2141
  // factory must retain the lowered callable rather than extracting a
2081
2142
  // fixed native signature from a checked value.
@@ -2117,16 +2178,40 @@ function bindableImplicitIr(t) {
2117
2178
  function storedImplicitArgumentType(lowerer, arg) {
2118
2179
  while (ts.isParenthesizedExpression(arg))
2119
2180
  arg = arg.expression;
2181
+ if (isJsSourceFile(arg.getSourceFile()) && (ts.isArrowFunction(arg) || ts.isFunctionExpression(arg))) {
2182
+ const saved = lowerer.diagSink;
2183
+ const diagnostics = [];
2184
+ lowerer.diagSink = diagnostics;
2185
+ let value;
2186
+ try {
2187
+ value = tryLowerExpression(lowerer, arg);
2188
+ }
2189
+ finally {
2190
+ lowerer.diagSink = saved;
2191
+ }
2192
+ // Direct inferred helpers can receive native callbacks even when their
2193
+ // result is an opaque handle that cannot cross checked storage.
2194
+ if (diagnostics.length === 0 && value?.type.kind === "func")
2195
+ return value.type;
2196
+ }
2197
+ if (arg.kind === ts.SyntaxKind.ThisKeyword)
2198
+ return lowerer.resolveThis()?.type ?? null;
2120
2199
  if (ts.isAwaitExpression(arg)) {
2121
2200
  const awaited = storedImplicitArgumentType(lowerer, arg.expression);
2122
2201
  return awaited?.kind === "promise" ? awaited.inner : awaited;
2123
2202
  }
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))
2203
+ if (ts.isObjectLiteralExpression(arg) && isJsSourceFile(arg.getSourceFile()) &&
2204
+ (arg.properties.length === 0 || arg.properties.some((property) => ts.isMethodDeclaration(property) || ts.isAccessor(property) ||
2205
+ !ts.isSpreadAssignment(property) && property.name !== undefined && ts.isComputedPropertyName(property.name))))
2126
2206
  return DYN;
2127
2207
  if (ts.isIdentifier(arg))
2128
2208
  return lowerer.peekLocal(arg)?.type ?? lowerer.globalOf(arg)?.type ?? null;
2129
2209
  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
+ }
2130
2215
  const callee = storedImplicitArgumentType(lowerer, arg.expression);
2131
2216
  if (callee?.kind === "dyn")
2132
2217
  return DYN;
@@ -2173,12 +2258,29 @@ export function implicitCallInstance(lowerer, call, info) {
2173
2258
  shapes.push({ type: stored, mode: "required" });
2174
2259
  return;
2175
2260
  }
2261
+ if (stored?.kind === "func") {
2262
+ // The lowered closure may have an inferred JS destructuring
2263
+ // parameter widened from the checker's exact tuple to dyn.
2264
+ // Preserve that signature throughout the specialization.
2265
+ const checkerType = lowerer.mapTypeOf(lowerer.typeOf(arg));
2266
+ argTypes.set(sym, checkerType && typeEquals(checkerType, stored)
2267
+ ? lowerer.typeOf(arg) : lowerer.checker.getUnknownType());
2268
+ shapes.push({ type: stored, mode: "required" });
2269
+ return;
2270
+ }
2176
2271
  // The argument's own checker type, literal-widened ('add' binds
2177
2272
  // string) — typeOf consults the ACTIVE instance's bindings, so a
2178
2273
  // bound param forwarded into another implicit call transitively
2179
2274
  // instantiates it (this._initCommandGroup(command)).
2180
2275
  const t = lowerer.checker.getBaseTypeOfLiteralType(lowerer.typeOf(arg));
2181
- const mapped = lowerer.mapTypeOf(t) ?? dynFallbackType(lowerer, arg, t);
2276
+ const mapped = (neverTaintedJsType(lowerer, arg, t) ? null : lowerer.mapTypeOf(t)) ?? dynFallbackType(lowerer, arg, t);
2277
+ if (isJsSourceFile(arg.getSourceFile()) && ts.isArrayLiteralExpression(arg) && mapped?.kind === "array" &&
2278
+ (mapped.elem.kind === "classval" || mapped.elem.kind === "union" &&
2279
+ lowerer.unions.get(mapped.elem.unionId)?.arms.every((arm) => arm.kind === "classval"))) {
2280
+ argTypes.set(sym, lowerer.checker.getUnknownType());
2281
+ shapes.push({ type: DYN, mode: "required" });
2282
+ return;
2283
+ }
2182
2284
  // JavaScript arguments-based callables travel as checked functions.
2183
2285
  // Specializing a parameter to the inferred rest signature would
2184
2286
  // require extracting a native variadic ABI that the value does not
@@ -2192,6 +2294,11 @@ export function implicitCallInstance(lowerer, call, info) {
2192
2294
  // That checker supertype is not an empty-record runtime layout:
2193
2295
  // preserve represented arms through the checked boundary instead
2194
2296
  // of specializing a call to a union that would discard them.
2297
+ if (isJsSourceFile(arg.getSourceFile()) && mapped?.kind === "func" && !lowerer.dynConvertible(mapped)) {
2298
+ argTypes.set(sym, lowerer.checker.getUnknownType());
2299
+ shapes.push({ type: DYN, mode: "required" });
2300
+ return;
2301
+ }
2195
2302
  const mappedArms = mapped?.kind === "union" ? lowerer.unions.get(mapped.unionId)?.arms ?? [] : mapped ? [mapped] : [];
2196
2303
  const hasTopObject = mappedArms.some((arm) => {
2197
2304
  const shape = arm.kind === "record" ? lowerer.shapes.get(arm.shapeId) : undefined;
@@ -2737,7 +2844,15 @@ export function lowerTimersMemberCall(lowerer, expr, member, loc) {
2737
2844
  if (expr.arguments.length !== 1) {
2738
2845
  lowerer.noLowering(`clearTimeout with ${expr.arguments.length} arguments`, expr);
2739
2846
  }
2740
- const handle = lowerer.lowerExpr(expr.arguments[0]);
2847
+ let handle = lowerer.lowerExpr(expr.arguments[0]);
2848
+ if (handle.type.kind === "dyn" && isJsSourceFile(expr.getSourceFile())) {
2849
+ const stored = lowerer.declareHiddenLocal("%timer.clear", DYN);
2850
+ const ref = varRef(stored.id, DYN, loc);
2851
+ handle = { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: stored.id, init: handle, loc }], result: {
2852
+ kind: "ternary", cond: { kind: "dynTest", test: "number", value: ref, type: BOOL, loc },
2853
+ then: lowerer.coerceInto(expr.arguments[0], ref, F64), else_: numLit(0, loc), type: F64, loc,
2854
+ }, type: F64, loc };
2855
+ }
2741
2856
  if (handle.type.kind !== "f64") {
2742
2857
  lowerer.noLowering(`clearTimeout of '${lowerer.fmt(handle.type)}' handles`, expr.arguments[0], "the handle is the Timeout setTimeout returned (narrow 'Timeout | null' first)");
2743
2858
  }
@@ -3264,6 +3379,14 @@ function lowerProjectedBuiltinCall(lowerer, expr, bi, loc) {
3264
3379
  }
3265
3380
  export function lowerCall(lowerer, expr) {
3266
3381
  const loc = locOf(expr);
3382
+ // Object's checker return type is `any`. Claim known object inputs
3383
+ // before generic checked-dynamic dispatch tries to load the constructor.
3384
+ if (ts.isIdentifier(expr.expression) && expr.expression.text === "Object" &&
3385
+ lowerer.isStdlibGlobal(expr.expression, "Object")) {
3386
+ const object = lowerObjectConstructor(lowerer, expr.arguments, loc);
3387
+ if (object)
3388
+ return object;
3389
+ }
3267
3390
  // A call whose chain ROOTS at an ambient-undefined name (`declare
3268
3391
  // const value: Y | undefined; value?.foo("a")`, `declare function
3269
3392
  // chain...; chain(o).mapValues(f).value()`, a trap binding's read):
@@ -3373,7 +3496,7 @@ export function lowerCall(lowerer, expr) {
3373
3496
  // `a?.m()` (the token on the member access). The handled markers keep
3374
3497
  // the chain lowering's re-entrant dispatch from looping.
3375
3498
  if ((expr.questionDotToken && !lowerer.chainHandled.has(expr)) ||
3376
- (ts.isPropertyAccessExpression(expr.expression) &&
3499
+ ((ts.isPropertyAccessExpression(expr.expression) || ts.isElementAccessExpression(expr.expression)) &&
3377
3500
  expr.expression.questionDotToken &&
3378
3501
  !lowerer.chainHandled.has(expr.expression))) {
3379
3502
  return lowerer.lowerOptionalChain(expr);
@@ -3382,6 +3505,9 @@ export function lowerCall(lowerer, expr) {
3382
3505
  // top-level statement (its field-initializer ordering lives there);
3383
3506
  // any other position would misorder initialization — rejected.
3384
3507
  if (expr.expression.kind === ts.SyntaxKind.SuperKeyword) {
3508
+ const superCall = lowerer.ctx.superCall;
3509
+ if (superCall)
3510
+ return superCall(expr);
3385
3511
  lowerer.unsupported("SC1090", expr, "super() calls anywhere but as a top-level constructor statement");
3386
3512
  }
3387
3513
  // super.method(...): a DIRECT (never virtual) call of the base chain's
@@ -3500,6 +3626,13 @@ export function lowerCall(lowerer, expr) {
3500
3626
  loc,
3501
3627
  });
3502
3628
  }
3629
+ if (ts.isPropertyAccessExpression(expr.expression) &&
3630
+ TIMER_MODULE_MEMBERS.has(expr.expression.name.text) &&
3631
+ lowerer.stdlibGlobalMember(expr.expression, "globalThis") === expr.expression.name.text) {
3632
+ const served = lowerTimersMemberCall(lowerer, expr, expr.expression.name.text, loc);
3633
+ if (served)
3634
+ return served;
3635
+ }
3503
3636
  // The timer globals — setTimeout/clearTimeout, setInterval/
3504
3637
  // clearInterval, setImmediate/clearImmediate. Provenance-checked (a
3505
3638
  // user function shadowing the name has a different, non-ambient
@@ -3642,9 +3775,7 @@ export function lowerCall(lowerer, expr) {
3642
3775
  // Provenance-checked like setTimeout; zero-arg forms are the JS
3643
3776
  // constants ("", false, 0). Wrapper objects stay fenced except where
3644
3777
  // 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)) {
3778
+ if (lowerer.isStdlibGlobal(expr.expression, "BigInt")) {
3648
3779
  if (expr.arguments.length !== 1) {
3649
3780
  lowerer.noLowering(`BigInt with ${expr.arguments.length} arguments`, expr);
3650
3781
  }
@@ -3657,12 +3788,11 @@ export function lowerCall(lowerer, expr) {
3657
3788
  return converted;
3658
3789
  lowerer.noLowering(`BigInt of ${lowerer.fmt(arg.type)} values`, argNode, "string, number, boolean, and bigint arguments are supported");
3659
3790
  }
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;
3791
+ if (lowerer.isStdlibGlobal(expr.expression, "String") ||
3792
+ lowerer.isStdlibGlobal(expr.expression, "Boolean") ||
3793
+ lowerer.isStdlibGlobal(expr.expression, "Number")) {
3794
+ const name = lowerer.isStdlibGlobal(expr.expression, "String") ? "String" :
3795
+ lowerer.isStdlibGlobal(expr.expression, "Boolean") ? "Boolean" : "Number";
3666
3796
  if (expr.arguments.length > 1) {
3667
3797
  lowerer.noLowering(`${name} with ${expr.arguments.length} arguments`, expr);
3668
3798
  }
@@ -3692,8 +3822,9 @@ export function lowerCall(lowerer, expr) {
3692
3822
  if (name === "Number")
3693
3823
  return lowerNumberConstructorValue(lowerer, argNode, loc);
3694
3824
  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 };
3825
+ if (name === "String" && (arg.type.kind === "dyn" || arg.type.kind === "union" &&
3826
+ lowerer.unions.get(arg.type.unionId)?.arms.some((arm) => arm.kind === "symbol") && lowerer.dynConvertible(arg.type))) {
3827
+ return { kind: "libCall", fn: "dyn.stringConstructor", args: [lowerer.coerceToExpected(arg, DYN)], type: STRING, loc };
3697
3828
  }
3698
3829
  if (name === "String")
3699
3830
  return lowerer.ensureString(arg, argNode);
@@ -3720,7 +3851,8 @@ export function lowerCall(lowerer, expr) {
3720
3851
  lowerer.fenceStaticHeadersMember(access, "call");
3721
3852
  lowerer.fenceStaticReadableStreamMember(access, "call");
3722
3853
  const source = tryLowerExpression(lowerer, access.expression);
3723
- if (source && (source.type.kind === "dyn" || isDynTypedRefType(source.type) &&
3854
+ if (source && (source.type.kind === "dyn" || source.type.kind === "func" ||
3855
+ (source.type.kind === "map" || source.type.kind === "set") && lowerer.dynConvertible(source.type) || isDynTypedRefType(source.type) &&
3724
3856
  lowerer.foldedStringKeyOf(access.argumentExpression) === null &&
3725
3857
  lowerer.mapTypeOf(lowerer.typeOf(access.argumentExpression))?.kind !== "symbol")) {
3726
3858
  const local = lowerer.declareHiddenLocal("%computedReceiver", DYN);
@@ -4123,6 +4255,7 @@ export function lowerCall(lowerer, expr) {
4123
4255
  // string-only argument rule.
4124
4256
  if ((expr.expression.text === "encodeURIComponent" ||
4125
4257
  expr.expression.text === "encodeURI" ||
4258
+ expr.expression.text === "decodeURI" ||
4126
4259
  expr.expression.text === "decodeURIComponent") &&
4127
4260
  lowerer.isStdlibSymbol(lowerer.resolveValueSymbol(expr.expression) ?? undefined)) {
4128
4261
  const name = expr.expression.text;
@@ -4131,10 +4264,10 @@ export function lowerCall(lowerer, expr) {
4131
4264
  }
4132
4265
  const loc = locOf(expr);
4133
4266
  const argNode = expr.arguments[0];
4134
- if (name === "decodeURIComponent") {
4267
+ if (name === "decodeURIComponent" || name === "decodeURI") {
4135
4268
  const d = optionalCallValue(lowerer, argNode) ?? lowerer.lowerExpr(argNode);
4136
4269
  const s = lowerer.ensureString(d, argNode);
4137
- return { kind: "libCall", fn: "str.decodeUriComponent", args: [s], type: STRING, loc };
4270
+ return { kind: "libCall", fn: name === "decodeURI" ? "str.decodeUri" : "str.decodeUriComponent", args: [s], type: STRING, loc };
4138
4271
  }
4139
4272
  const value = optionalCallValue(lowerer, argNode) ?? lowerer.lowerExpr(argNode);
4140
4273
  const s = lowerer.ensureString(value, argNode);
@@ -4415,7 +4548,8 @@ export function lowerCall(lowerer, expr) {
4415
4548
  lowerer.lowerJsonMethodCall(expr, expr.expression) ??
4416
4549
  // Reflect.apply of a builtin rest-parameter fn (fixtures.js's
4417
4550
  // fixturesPath idiom) — before the stdlib member fence claims it.
4418
- lowerReflectApplyCall(lowerer, expr, expr.expression) ??
4551
+ lowerReflectCall(lowerer, expr, expr.expression) ??
4552
+ lowerBigIntStaticCall(lowerer, expr, expr.expression) ??
4419
4553
  lowerer.lowerNumberStaticCall(expr, expr.expression) ??
4420
4554
  lowerer.lowerDateCall(expr, expr.expression) ??
4421
4555
  lowerer.lowerTextCodecCall(expr, expr.expression) ??
@@ -4487,8 +4621,8 @@ export function lowerCall(lowerer, expr) {
4487
4621
  // Readable.from — the stream classes' one static (before the
4488
4622
  // stdlib chokepoint claims the member).
4489
4623
  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.
4624
+ // Primitive toString calls, including numeric radices, use the
4625
+ // native formatters before the island method path.
4492
4626
  lowerNumberToStringCall(lowerer, expr, expr.expression) ??
4493
4627
  // Union receivers whose every arm has a text — the ngrok
4494
4628
  // `(chunk: Buffer | string) => chunk.toString()` idiom.
@@ -4528,7 +4662,6 @@ export function lowerCall(lowerer, expr) {
4528
4662
  // by the receiver's own element.
4529
4663
  lowerer.lowerFilterNarrowCall(expr, expr.expression) ??
4530
4664
  lowerArrayIsArrayCall(lowerer, expr, expr.expression) ??
4531
- lowerBigIntStaticCall(lowerer, expr, expr.expression) ??
4532
4665
  lowerBigIntMethodCall(lowerer, expr, expr.expression) ??
4533
4666
  lowerSymbolStaticCall(lowerer, expr, expr.expression) ??
4534
4667
  lowerSymbolMethodCall(lowerer, expr, expr.expression) ??
@@ -4563,6 +4696,13 @@ export function lowerCall(lowerer, expr) {
4563
4696
  lowerObjLitGenericMethodCall(lowerer, expr, expr.expression);
4564
4697
  if (intrinsic)
4565
4698
  return intrinsic;
4699
+ if (isJsSourceFile(expr.getSourceFile())) {
4700
+ const staticField = lowerStaticFieldRead(lowerer, expr.expression);
4701
+ if (staticField?.type.kind === "dyn" && !expr.arguments.some(ts.isSpreadElement)) {
4702
+ return { kind: "dynCall", callee: staticField, receiver: lowerer.lowerExprExpecting(expr.expression.expression, DYN), calleeName: expr.expression.getText(),
4703
+ args: expr.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc: locOf(expr) };
4704
+ }
4705
+ }
4566
4706
  const accessorTarget = lowerer.fieldTarget(expr.expression);
4567
4707
  if (accessorTarget?.container === "accessor") {
4568
4708
  const callee = lowerer.fieldGetExpr(accessorTarget, locOf(expr.expression), expr.expression);
@@ -4635,6 +4775,30 @@ export function lowerCall(lowerer, expr) {
4635
4775
  lowerer.fenceStaticHeadersMember(expr.expression, "call");
4636
4776
  lowerer.fenceStaticReadableStreamMember(expr.expression, "call");
4637
4777
  }
4778
+ // Computed native members retain their original receiver and resolve
4779
+ // the function before argument effects, just like dotted calls.
4780
+ if (ts.isElementAccessExpression(expr.expression) && !expr.expression.questionDotToken && !expr.questionDotToken &&
4781
+ !symbolFieldInfo(lowerer, expr.expression)) {
4782
+ const access = expr.expression;
4783
+ const value = tryLowerExpression(lowerer, access.expression);
4784
+ if (value?.type.kind === "dyn" || value?.type.kind === "generator" ||
4785
+ value && ["array", "bytes", "map", "set"].includes(value.type.kind) && lowerer.dynConvertible(value.type) ||
4786
+ value?.type.kind === "string" && !ts.isStringLiteralLike(access.argumentExpression) && lowerer.dynConvertible(value.type) ||
4787
+ value?.type.kind === "object" && !lowerer.classes.get(value.type.className)?.def.runtime) {
4788
+ const local = lowerer.declareHiddenLocal("%computedReceiver", value.type);
4789
+ const reference = { kind: "varRef", localId: local.id, type: value.type, loc };
4790
+ const receiver = lowerer.coerceToExpected(reference, DYN);
4791
+ const raw = lowerer.lowerExpr(access.argumentExpression);
4792
+ const key = raw.type.kind === "string" ? raw : lowerer.coerceInto(access.argumentExpression, raw, DYN);
4793
+ const callee = { kind: "dynKeyGet", value: receiver, key, type: DYN, loc };
4794
+ const spread = expr.arguments.some(ts.isSpreadElement) ? lowerSpreadArgsCall(lowerer, expr, callee, loc) : null;
4795
+ if (spread && spread.kind !== "dynCall")
4796
+ lowerer.unsupported("SC1090", expr, "computed native method spread arguments");
4797
+ const result = spread !== null ? { ...spread, receiver } : { kind: "dynCall", callee, receiver,
4798
+ calleeName: access.getText(), args: expr.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
4799
+ return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id, init: value, loc }], result, type: DYN, loc };
4800
+ }
4801
+ }
4638
4802
  // The ELEMENT spelling of a primitive method call — `x['toString']()`,
4639
4803
  // `s['charAt'](0)`: JS resolves it exactly like the dot form, so the
4640
4804
  // literal-keyed shapes with a static lowering route there before the
@@ -4720,6 +4884,11 @@ export function lowerCall(lowerer, expr) {
4720
4884
  : "value";
4721
4885
  return { kind: "dynCall", callee, calleeName, args, type: DYN, loc };
4722
4886
  }
4887
+ if (callee.type.kind === "union" && lowerer.dynConvertible(callee.type) &&
4888
+ lowerer.unions.get(callee.type.unionId)?.arms.some((arm) => arm.kind === "func")) {
4889
+ return { kind: "dynCall", callee: lowerer.coerceToExpected(callee, DYN), calleeName: expr.expression.getText(),
4890
+ args: expr.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
4891
+ }
4723
4892
  if (callee.type.kind !== "func") {
4724
4893
  lowerer.badType(expr.expression, lowerer.typeOf(expr.expression));
4725
4894
  }
@@ -4959,6 +5128,10 @@ function lowerNumberConstructorValue(lowerer, argNode, loc) {
4959
5128
  return { kind: "libCall", fn: "num.fromString", args: [arg], type: F64, loc };
4960
5129
  if (arg.type.kind === "dyn")
4961
5130
  return { kind: "libCall", fn: "dyn.numberConstructor", args: [arg], type: F64, loc };
5131
+ if (arg.type.kind === "union" && lowerer.dynConvertible(arg.type))
5132
+ return {
5133
+ kind: "libCall", fn: "dyn.numberConstructor", args: [lowerer.coerceToExpected(arg, DYN)], type: F64, loc,
5134
+ };
4962
5135
  const optionalNumber = lowerOptionalStringNumber(lowerer, arg, loc);
4963
5136
  if (optionalNumber)
4964
5137
  return optionalNumber;
@@ -4973,6 +5146,8 @@ function lowerNumberConstructorValue(lowerer, argNode, loc) {
4973
5146
  * checker guard. Dispatch BigInt by the actual value, including nullish
4974
5147
  * TypeErrors, rather than interpreting that storage as the narrowed arm. */
4975
5148
  function lowerBigIntConstructorValue(lowerer, arg, loc) {
5149
+ if (arg.type.kind === "dyn")
5150
+ return { kind: "libCall", fn: "dyn.bigintConstructor", args: [arg], type: BIGINT_T, loc };
4976
5151
  if (arg.type.kind === "bigint")
4977
5152
  return arg;
4978
5153
  if (arg.type.kind === "string")
@@ -5244,8 +5419,9 @@ function lowerObjectOwnCall(lowerer, call, receiverNode, keyNode, extraNodes, me
5244
5419
  stmts.push({ kind: "exprStmt", expr: effect, loc: locOf(extra) });
5245
5420
  }
5246
5421
  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 };
5422
+ if (lowerer.dynConvertible(receiverRef.type) && keyRef && (receiverRef.type.kind === "object" || keyRef.type.kind === "symbol" || keyRef.type.kind === "dyn" ||
5423
+ keyRef.type.kind === "union" && lowerer.dynConvertible(keyRef.type))) {
5424
+ const result = { kind: "libCall", fn: enumerable ? "dyn.propertyIsEnumerableComputed" : "dyn.hasOwnComputed", args: [lowerer.coerceToExpected(receiverRef, DYN), lowerer.coerceToExpected(keyRef, DYN)], type: BOOL, loc };
5249
5425
  return { kind: "seqExpr", stmts, result, type: BOOL, loc };
5250
5426
  }
5251
5427
  if (!keyNode || rawKey?.type.kind === "undefinedT" || rawKey?.type.kind === "void") {
@@ -5441,6 +5617,9 @@ function lowerStringPrototypeCall(lowerer, call, access) {
5441
5617
  // padding uses a helper that delays conversion until every argument is ready.
5442
5618
  const objectWithoutMethodArgs = entry?.maxArgs === 0 && call.arguments.length === 1 &&
5443
5619
  (receiverType.kind === "record" || receiverType.kind === "array" || receiverType.kind === "object");
5620
+ if (padding && !scalar && lowerer.dynConvertible(receiverType)) {
5621
+ return lowerStringPaddingCall(lowerer, call, entry.method, lowerer.coerceToExpected(receiverValue, DYN), receiverNode, call.arguments.slice(1));
5622
+ }
5444
5623
  if (!scalar && !objectWithoutMethodArgs) {
5445
5624
  lowerer.noLowering(`String.prototype.${methodAccess.name.text}.call with ${lowerer.fmt(receiverType)} receivers`, call);
5446
5625
  }
@@ -5677,7 +5856,7 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
5677
5856
  // tsc types the return by the evolved shape, the binding lowered
5678
5857
  // dyn): probe the lowering and claim exactly the dyn results.
5679
5858
  const probed = tryLowerExpression(lowerer, access.expression);
5680
- if (isJsSourceFile(call.getSourceFile()) && probed?.type.kind === "func" &&
5859
+ if (probed?.type.kind === "func" && stdlibGlobalNameOf(lowerer, access.expression) === null &&
5681
5860
  !["call", "apply", "bind", "toString", "valueOf", "constructor"].includes(access.name.text) &&
5682
5861
  canBoxFuncIntoDyn(probed.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
5683
5862
  const loc = locOf(call);
@@ -5698,10 +5877,22 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
5698
5877
  args: call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc }, type: DYN, loc,
5699
5878
  };
5700
5879
  }
5880
+ if (probed?.type.kind === "classval") {
5881
+ const info = lowerer.classes.get(probed.type.className);
5882
+ if (info && (info.callableBase || hasRuntimeStatics(info)))
5883
+ return lowerStaticMethodCall(lowerer, call, access);
5884
+ }
5701
5885
  if (probed?.type.kind !== "dyn")
5702
5886
  return null;
5703
5887
  recv = probed;
5704
5888
  }
5889
+ // A factory may return a constructor more precise than its inferred
5890
+ // checker result. Runtime static members live on that constructor.
5891
+ if (recv.type.kind === "classval") {
5892
+ const info = lowerer.classes.get(recv.type.className);
5893
+ if (info && (info.callableBase || hasRuntimeStatics(info)))
5894
+ return lowerStaticMethodCall(lowerer, call, access);
5895
+ }
5705
5896
  // A checker-`any` receiver that already lowered to a real STRING (the
5706
5897
  // chained form — `cfg.host.trim().toLowerCase()`, where the first step
5707
5898
  // extracted): no validation needed, ride the string tables directly.
@@ -5770,7 +5961,13 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
5770
5961
  // unimplemented methods throw a LOUD not-supported Error; names the
5771
5962
  // kind's prototype lacks throw Node's "x.y is not a function"; OBJ
5772
5963
  // receivers call the own member.
5773
- const dispatched = lowerDynDispatchMethodCall(lowerer, call, access, recv, arrayReceiver);
5964
+ // A stored callback must be read before argument effects, and called
5965
+ // with the original receiver rather than a materialized property view.
5966
+ const callbackProperty = (() => {
5967
+ const prop = lowerer.checker.getPropertyOfType(recvTs, access.name.text);
5968
+ return prop !== undefined && lowerer.checker.declarationsOf(prop).some((decl) => ts.isPropertyDeclaration(decl) || ts.isPropertySignature(decl));
5969
+ })();
5970
+ const dispatched = callbackProperty ? null : lowerDynDispatchMethodCall(lowerer, call, access, recv, arrayReceiver);
5774
5971
  if (dispatched)
5775
5972
  return dispatched;
5776
5973
  // Names NO dyn-representable prototype declares: the member can only
@@ -5796,9 +5993,6 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
5796
5993
  if (call.questionDotToken || access.questionDotToken)
5797
5994
  return null;
5798
5995
  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
5996
  const receiverLocal = lowerer.declareHiddenLocal("%dynCallReceiver", DYN);
5803
5997
  const receiver = { kind: "varRef", localId: receiverLocal.id, type: DYN, loc };
5804
5998
  const member = {
@@ -5808,6 +6002,14 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
5808
6002
  type: DYN,
5809
6003
  loc: locOf(access),
5810
6004
  };
6005
+ if (call.arguments.some(ts.isSpreadElement)) {
6006
+ const spread = lowerSpreadArgsCall(lowerer, call, member, loc);
6007
+ if (spread?.kind === "dynCall")
6008
+ return { kind: "seqExpr",
6009
+ stmts: [{ kind: "varDecl", localId: receiverLocal.id, init: recv, loc }],
6010
+ result: { ...spread, receiver }, type: DYN, loc };
6011
+ lowerer.unsupported("SC1090", call, "spread arguments in calls through 'unknown' values");
6012
+ }
5811
6013
  const args = call.arguments.map((a) => lowerer.lowerExprExpecting(a, DYN));
5812
6014
  return {
5813
6015
  kind: "seqExpr", stmts: [{ kind: "varDecl", localId: receiverLocal.id, init: recv, loc }],
@@ -5858,7 +6060,7 @@ const DYN_DISPATCH_METHODS = new Set([
5858
6060
  "setEncoding", "setDefaultEncoding", "setTimeout", "read", "isPaused",
5859
6061
  "writeHead", "setHeader", "getHeader", "hasHeader", "removeHeader",
5860
6062
  "getHeaders", "getHeaderNames", "appendHeader", "flushHeaders",
5861
- "add", "append", "delete", "get", "getSetCookie", "has", "set",
6063
+ "add", "append", "delete", "get", "getSetCookie", "has", "set", "clear", "keys", "values", "entries", "next",
5862
6064
  "writeContinue", "writeEarlyHints", "cork", "uncork", "addTrailers",
5863
6065
  "ref", "unref", "address", "setNoDelay", "setKeepAlive", "connect",
5864
6066
  "resetAndDestroy", "destroySoon",
@@ -5879,7 +6081,7 @@ const DYN_DISPATCH_METHODS = new Set([
5879
6081
  "dispatchEvent",
5880
6082
  "preventDefault", "stopPropagation", "stopImmediatePropagation",
5881
6083
  "composedPath",
5882
- "json", "text", "bytes",
6084
+ "json", "text", "bytes", "arrayBuffer",
5883
6085
  // Promise.prototype (SCR_DYN_PROMISE receivers): the reaction trio
5884
6086
  // rides the fiber machinery (scr_dyn_promise_then); on every other dyn
5885
6087
  // kind then/catch/finally answer the stored-member path (OBJ own
@@ -5899,6 +6101,17 @@ export function lowerDynDispatchMethodCall(lowerer, call, access, recv, arrayRec
5899
6101
  if ((!DYN_DISPATCH_METHODS.has(method) && !isJsSourceFile(call.getSourceFile())) || lowerer.chainBlocked(call, access))
5900
6102
  return null;
5901
6103
  if (call.arguments.some((arg) => ts.isSpreadElement(arg))) {
6104
+ const loc = locOf(call);
6105
+ const local = lowerer.declareHiddenLocal("%spreadReceiver", DYN);
6106
+ const receiver = varRef(local.id, DYN, loc);
6107
+ const callee = { kind: "dynKeyGet", value: receiver,
6108
+ key: { kind: "strLit", value: method, type: STRING, loc }, type: DYN, loc };
6109
+ const spread = lowerSpreadArgsCall(lowerer, call, callee, loc);
6110
+ if (spread?.kind === "dynCall")
6111
+ return { kind: "seqExpr",
6112
+ stmts: [{ kind: "varDecl", localId: local.id, init: recv, loc },
6113
+ { kind: "exprStmt", expr: { kind: "libCall", fn: "dyn.arrayPrototype", args: [], type: DYN, loc }, loc }],
6114
+ result: { ...spread, receiver }, type: DYN, loc };
5902
6115
  lowerer.unsupported("SC1090", call, "spread arguments in calls through 'unknown' values");
5903
6116
  }
5904
6117
  const predicate = method === "filter" && call.arguments[0]
@@ -5972,7 +6185,12 @@ export function lowerDynDispatchMethodCall(lowerer, call, access, recv, arrayRec
5972
6185
  }
5973
6186
  }
5974
6187
  }
5975
- const args = call.arguments.map((arg, i) => i === 0 && predicate ? lowerer.coerceInto(arg, predicate, DYN) : lowerer.lowerExprExpecting(arg, DYN));
6188
+ const args = call.arguments.map((arg, i) => {
6189
+ if (i === 0 && predicate)
6190
+ return lowerer.coerceInto(arg, predicate, DYN);
6191
+ const undefinedArg = lowerStaticallyUndefinedArgument(lowerer, arg);
6192
+ return undefinedArg ? defaultAfterUndefined(undefinedArg, dynUndefinedExpr(locOf(arg))) : lowerer.lowerExprExpecting(arg, DYN);
6193
+ });
5976
6194
  return {
5977
6195
  kind: "dynInvoke",
5978
6196
  recv,
@@ -6098,13 +6316,13 @@ function lowerCaughtPredicateCall(lowerer, call, caughtLocal) {
6098
6316
  * and String(n) lower to (Number::toString with radix 10 IS that
6099
6317
  * conversion, per spec) — booleans the "true"/"false" texts, and strings
6100
6318
  * the identity read (String.prototype.toString returns `this`). The
6101
- * explicit-radix number form keeps its island lowering (ISLAND_SURFACE);
6319
+ * explicit-radix number form uses the native radix formatter;
6102
6320
  * null for other receivers, argument shapes, or non-lib members (a
6103
6321
  * user's own `.toString` takes the ordinary paths). */
6104
6322
  function lowerNumberToStringCall(lowerer, call, access) {
6105
6323
  if (lowerer.chainBlocked(call, access))
6106
6324
  return null;
6107
- if (access.name.text !== "toString" || call.arguments.length !== 0)
6325
+ if (access.name.text !== "toString" || call.arguments.length > 1 || call.arguments.some(ts.isSpreadElement))
6108
6326
  return null;
6109
6327
  const recvKind = lowerer.mapTypeOf(lowerer.typeOf(access.expression))?.kind;
6110
6328
  if (recvKind !== "f64" && recvKind !== "bool" && recvKind !== "string")
@@ -6112,6 +6330,22 @@ function lowerNumberToStringCall(lowerer, call, access) {
6112
6330
  if (!lowerer.isStdlibMember(access))
6113
6331
  return null;
6114
6332
  const operand = lowerer.lowerExpr(access.expression);
6333
+ // JavaScript array and typed-array reads can still be undefined even
6334
+ // when the checker declares a number. Preserve that runtime value and
6335
+ // let native method dispatch format numbers or throw for missing data.
6336
+ if (operand.type.kind === "dyn") {
6337
+ return {
6338
+ kind: "libCall", fn: "dyn.toString", args: [operand,
6339
+ call.arguments[0] ? lowerer.lowerExprExpecting(call.arguments[0], DYN) : dynUndefinedExpr(locOf(call)),
6340
+ { kind: "strLit", value: access.getText(), type: STRING, loc: locOf(call) },
6341
+ ], type: STRING, loc: locOf(call),
6342
+ };
6343
+ }
6344
+ if (call.arguments.length === 1) {
6345
+ if (operand.type.kind !== "f64")
6346
+ return null;
6347
+ return { kind: "libCall", fn: "num.toStringRadix", args: [operand, lowerer.lowerExprExpecting(call.arguments[0], DYN)], type: STRING, loc: locOf(call) };
6348
+ }
6115
6349
  if (operand.type.kind === "string")
6116
6350
  return operand; // identity, receiver evaluated
6117
6351
  if (operand.type.kind !== "f64" && operand.type.kind !== "bool")
@@ -6574,15 +6808,14 @@ function templateEscapesValid(raw) {
6574
6808
  * maps to string[] (type-mapper.ts), so the array rides the ordinary
6575
6809
  * slot-directed coercion into whatever the tag's first parameter wants
6576
6810
  * — 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).
6811
+ * pack's first element. Checked tags receive frozen cooked and raw
6812
+ * arrays with the standard nonenumerable `.raw` descriptor. Typed direct
6813
+ * tags retain the string-array representation.
6580
6814
  *
6581
6815
  * Tag forms: a top-level declared function (the direct-call fast path —
6582
6816
  * overload sets reconcile through the resolved signature exactly like
6583
6817
  * 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
6818
+ * call with the engine's cooked/raw template object), and
6586
6819
  * a checked-dynamic value (the dynCall boundary — a non-function tag
6587
6820
  * throws Node's catchable TypeError). Everything else — generic tags,
6588
6821
  * method tags, function-value bindings — fences by name. */
@@ -6642,10 +6875,11 @@ export function lowerTaggedTemplate(lowerer, expr) {
6642
6875
  if (ts.isIdentifier(expr.tag) && !lowerer.isSelfReference(expr.tag)) {
6643
6876
  if (lowerer.isTopLevelFnSymbol(expr.tag) && !lowerer.peekLocal(expr.tag)) {
6644
6877
  fenceEarlyAliasUse(lowerer, expr.tag, expr);
6645
- if (lowerer.genericFnOf(expr.tag)) {
6878
+ const genericTag = lowerer.genericFnOf(expr.tag);
6879
+ if (genericTag && !genericTag.implicitParams) {
6646
6880
  lowerer.unsupported("SC1090", expr, "tagged templates with generic tag functions");
6647
6881
  }
6648
- const sig = lowerer.fnSigOf(expr.tag);
6882
+ const sig = genericTag ? null : lowerer.fnSigOf(expr.tag);
6649
6883
  if (sig) {
6650
6884
  lowerer.noteEdge(sig.name);
6651
6885
  const args = completeArgs(lowerer, values, sig.params, loc, expr, [strings()]);
@@ -6672,10 +6906,13 @@ export function lowerTaggedTemplate(lowerer, expr) {
6672
6906
  // Checked-dynamic tags (`var f: any; f\`abc\``, dyn property chains):
6673
6907
  // the dynCall boundary — arguments convert into dyn, a non-function
6674
6908
  // tag throws Node's catchable "<name> is not a function" TypeError.
6675
- const callee = lowerer.lowerExpr(expr.tag);
6909
+ let callee = lowerer.lowerExpr(expr.tag);
6910
+ if (callee.type.kind === "func" && isJsSourceFile(expr.getSourceFile()) && lowerer.dynConvertible(callee.type)) {
6911
+ callee = { kind: "dynFrom", value: callee, type: DYN, loc };
6912
+ }
6676
6913
  if (callee.type.kind === "dyn") {
6677
6914
  const args = [
6678
- lowerer.coerceInto(expr.template, strings(), DYN),
6915
+ loweredTemplateStrings(lowerer, expr, pieces.map((piece) => piece.text), loc, pieces.map(templateRawTextOf)),
6679
6916
  ...values.map((a) => lowerer.lowerExprExpecting(a, DYN)),
6680
6917
  ];
6681
6918
  const calleeName = ts.isPropertyAccessExpression(expr.tag) || ts.isElementAccessExpression(expr.tag)
@@ -6687,12 +6924,15 @@ export function lowerTaggedTemplate(lowerer, expr) {
6687
6924
  }
6688
6925
  lowerer.unsupported("SC1090", expr, "tagged templates with this tag form (top-level functions and dynamic values tag; call the function directly otherwise)");
6689
6926
  }
6690
- function loweredTemplateStrings(lowerer, expr, cooked, loc) {
6927
+ function loweredTemplateStrings(lowerer, expr, cooked, loc, raw) {
6691
6928
  // Normal runtime construction keeps this array aligned with the current
6692
6929
  // ScrArr layout in the backend. The old static-header IR node encoded the
6693
6930
  // 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()}`;
6931
+ const type = raw ? DYN : arrayOf(STRING);
6932
+ const array = (values) => ({ kind: "dynArrLit", elems: values.map((value) => ({ kind: "dynFrom", value: { kind: "strLit", value, type: STRING, loc }, type: DYN, loc })), type: DYN, loc });
6933
+ const freeze = (value) => ({ kind: "libCall", fn: "dyn.freeze", args: [value], type: DYN, loc });
6934
+ 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;
6935
+ const key = `templateStringsGlobal:${loc.file}:${expr.template.getStart()}:${raw ? "checked" : "typed"}`;
6696
6936
  let getter = lowerer.widthHelpers.get(key);
6697
6937
  if (!getter) {
6698
6938
  const site = lowerer.globalsList.length;
@@ -6714,7 +6954,7 @@ function loweredTemplateStrings(lowerer, expr, cooked, loc) {
6714
6954
  {
6715
6955
  kind: "assign",
6716
6956
  localId: globalId,
6717
- value: {
6957
+ value: checked ?? {
6718
6958
  kind: "arrayLit",
6719
6959
  elems: cooked.map((value) => ({ kind: "strLit", value, type: STRING, loc })),
6720
6960
  type,
@@ -6819,6 +7059,23 @@ export function lambdaSignature(lowerer, node) {
6819
7059
  : "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
7060
  }
6821
7061
  const shapes = lowerer.paramShapes(node.parameters);
7062
+ // Error-first callbacks captured by native filesystem adapters receive
7063
+ // the selected runtime overload. Ambient contextual inference can pick
7064
+ // the string overload even when options request a Buffer.
7065
+ if ((ts.isArrowFunction(node) || ts.isFunctionExpression(node)) && ts.isCallExpression(node.parent) &&
7066
+ node.parent.arguments.at(-1) === node) {
7067
+ const builtin = ts.isPropertyAccessExpression(node.parent.expression) ? lowerer.builtinMemberOf(node.parent.expression)
7068
+ : ts.isIdentifier(node.parent.expression) ? lowerer.builtinImportOf(node.parent.expression) : null;
7069
+ if (builtin?.module === "fs" && builtin.member !== "rename" && builtinModuleFnOf(lowerer, builtin.module, builtin.member)?.fn === "fs.callbackCall") {
7070
+ for (let index = 0; index < shapes.length; index++) {
7071
+ if (!node.parameters[index]?.type) {
7072
+ shapes[index].type = DYN;
7073
+ if (shapes[index].bodyType)
7074
+ shapes[index].bodyType = DYN;
7075
+ }
7076
+ }
7077
+ }
7078
+ }
6822
7079
  // A concise arrow over an h2-only stream/session call (`() =>
6823
7080
  // req.stream.destroy()`): the call ALWAYS throws on this lowering
6824
7081
  // (stream is undefined — the streamUndefCall precedent), so the body
@@ -6919,14 +7176,21 @@ export function lambdaSignature(lowerer, node) {
6919
7176
  * object-literal shorthand method to a module-level function and yields
6920
7177
  * the `closure` expression creating it. */
6921
7178
  export function lowerLambda(lowerer, node) {
7179
+ const prepared = (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) ? lowerer.preparedClassFactories.get(node) : undefined;
7180
+ if (prepared)
7181
+ return prepared;
6922
7182
  const loc = locOf(node);
6923
- const { shapes, funcType } = lowerer.lambdaSignature(node);
7183
+ const signature = lowerer.lambdaSignature(node);
7184
+ const { shapes } = signature;
7185
+ let { funcType } = signature;
6924
7186
  // A lambda IS a value: the completed-ABI rule applies at birth. The
6925
7187
  // contextual (target) type decides — `(x?: number) => void` may flow
6926
7188
  // into a slot annotated `(x: number | undefined) => void` (same ABI
6927
7189
  // signature), anything else is fenced. Nested function declarations and
6928
7190
  // object-literal shorthand methods aren't expressions — always fenced.
6929
- lowerer.requireExactArityValue(node, ts.isArrowFunction(node) || ts.isFunctionExpression(node) ? node : null, shapes, funcType);
7191
+ if (!(ts.isMethodDeclaration(node) && isJsSourceFile(node.getSourceFile()) &&
7192
+ canBoxFuncIntoDyn(funcType, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))))
7193
+ lowerer.requireExactArityValue(node, ts.isArrowFunction(node) || ts.isFunctionExpression(node) ? node : null, shapes, funcType);
6930
7194
  const nameIdent = !ts.isArrowFunction(node) && node.name && ts.isIdentifier(node.name) ? node.name : null;
6931
7195
  const baseName = nameIdent ? nameIdent.text : "";
6932
7196
  const fnName = `%fn${lowerer.lambdaCounter++}${baseName ? `_${baseName}` : ""}`;
@@ -6950,10 +7214,18 @@ export function lowerLambda(lowerer, node) {
6950
7214
  if (isGenerator &&
6951
7215
  (funcType.ret.kind !== "generator" || (funcType.ret.async === true) !== isAsync))
6952
7216
  lowerer.badType(node, lowerer.typeOf(node));
6953
- const bodyReturn = isGenerator
7217
+ let bodyReturn = isGenerator
6954
7218
  ? lowerer.genBodyReturnType(funcType.ret)
6955
7219
  : lowerer.bodyReturnType(isAsync, funcType.ret);
6956
7220
  const fnCtx = newFnCtx(true, selfSymbol, funcType, bodyReturn);
7221
+ const inferredSignature = isJsSourceFile(node.getSourceFile()) && !node.type ? lowerer.checker.getSignatureFromDeclaration(node) : undefined;
7222
+ const returnsConstructor = inferredSignature && producesConstructor(lowerer, lowerer.checker.getReturnTypeOfSignature(inferredSignature));
7223
+ if (isJsSourceFile(node.getSourceFile()) && !node.type && !isAsync && !isGenerator &&
7224
+ (bodyReturn.kind === "classval" || bodyReturn.kind === "date" || bodyReturn.kind === "symbol" || bodyReturn.kind === "record" ||
7225
+ (bodyReturn.kind === "dyn" || bodyReturn.kind === "func") && returnsConstructor)) {
7226
+ fnCtx.inferReturn = { entries: [] };
7227
+ }
7228
+ fnCtx.inheritsArguments = ts.isArrowFunction(node);
6957
7229
  fnCtx.isAsync = isAsync;
6958
7230
  if (isGenerator && funcType.ret.kind === "generator") {
6959
7231
  fnCtx.generator = generatorMeta(lowerer, funcType.ret);
@@ -6967,7 +7239,7 @@ export function lowerLambda(lowerer, node) {
6967
7239
  // and a method nested inside another method never captures its owner.
6968
7240
  if (isJsSourceFile(node.getSourceFile()) && !ts.isArrowFunction(node)) {
6969
7241
  const receiver = lowerer.declareThis(DYN);
6970
- prologue.unshift({ kind: "varDecl", localId: receiver.id, init: { kind: "libCall", fn: "dyn.this", args: [], type: DYN, loc }, loc });
7242
+ prologue.unshift({ kind: "varDecl", localId: receiver.id, init: { kind: "libCall", fn: isGenerator ? "dyn.generatorThis" : "dyn.this", args: [], type: DYN, loc }, loc });
6971
7243
  }
6972
7244
  // The synthetic trailing dyn-array param carries `arguments`.
6973
7245
  // Parameterized functions receive all actual arguments; zero-param
@@ -6977,6 +7249,15 @@ export function lowerLambda(lowerer, node) {
6977
7249
  params.push({ localId: argsLocal.id, name: "%arguments", type: DYN });
6978
7250
  fnCtx.argumentsLocal = argsLocal;
6979
7251
  }
7252
+ if (isJsSourceFile(node.getSourceFile()) && !ts.isArrowFunction(node) &&
7253
+ shapes.length === 1 && shapes[0]?.mode === "dynRest" && bodyReadsArguments(node)) {
7254
+ const argsLocal = lowerer.declareHiddenLocal("%arguments", DYN);
7255
+ prologue.push({ kind: "varDecl", localId: argsLocal.id, init: {
7256
+ kind: "dynInvoke", recv: varRef(params[0].localId, DYN, loc), method: "slice",
7257
+ calleeName: "Array.prototype.slice", args: [], type: DYN, loc,
7258
+ }, loc });
7259
+ fnCtx.argumentsLocal = argsLocal;
7260
+ }
6980
7261
  let body;
6981
7262
  if (ts.isBlock(node.body)) {
6982
7263
  body = lowerer.lowerStmts(node.body.statements);
@@ -7011,7 +7292,7 @@ export function lowerLambda(lowerer, node) {
7011
7292
  else {
7012
7293
  // Concise and block bodies use the same destination layout for
7013
7294
  // fresh literals. Async bodies must inspect promises first.
7014
- let value = isAsync ? lowerer.lowerExpr(bodyExpr) : lowerer.lowerExprExpecting(bodyExpr, bodyReturn);
7295
+ let value = isAsync || fnCtx.inferReturn ? lowerer.lowerExpr(bodyExpr) : lowerer.lowerExprExpecting(bodyExpr, bodyReturn);
7015
7296
  // An async concise body whose value is itself a promise
7016
7297
  // (`async () => p`): the async machinery RESOLVES the returned
7017
7298
  // thenable into the function's own promise — lowerReturnValue's
@@ -7025,17 +7306,25 @@ export function lowerLambda(lowerer, node) {
7025
7306
  : [
7026
7307
  {
7027
7308
  kind: "return",
7028
- value: lowerer.coerceInto(bodyExpr, value, bodyReturn),
7309
+ value: fnCtx.inferReturn ? value : lowerer.coerceInto(bodyExpr, value, bodyReturn),
7029
7310
  loc: locOf(node.body),
7030
7311
  },
7031
7312
  ];
7313
+ if (fnCtx.inferReturn && body[0]?.kind === "return")
7314
+ fnCtx.inferReturn.entries.push({ stmt: body[0], node: bodyExpr });
7032
7315
  }
7033
7316
  }
7317
+ if (fnCtx.inferReturn) {
7318
+ bodyReturn = resolveInferredReturn(lowerer, { returnType: bodyReturn }, fnCtx.inferReturn, body, node);
7319
+ funcType = { ...funcType, ret: bodyReturn };
7320
+ fnCtx.returnType = bodyReturn;
7321
+ }
7034
7322
  body = [...prologue, ...body];
7035
7323
  // Bare-expression bodies never pass through lowerStmts, so the
7036
7324
  // lib-boundary chokepoint runs here (idempotent for block bodies,
7037
7325
  // whose statements were already walked). A fence poisons the
7038
7326
  // enclosing statement — the lambda IS part of it.
7327
+ body = lowerSurplusCalls(lowerer, body);
7039
7328
  enforceLibBoundary(lowerer, body);
7040
7329
  appendImplicitUndefinedReturn(lowerer, body, bodyReturn, loc);
7041
7330
  const ctx = lowerer.ctx;
@@ -7189,7 +7478,7 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
7189
7478
  const member = access.name.text;
7190
7479
  if (member !== "then" && member !== "catch" && member !== "finally")
7191
7480
  return null;
7192
- let recvT = lowerer.mapTypeOf(lowerer.typeOf(access.expression));
7481
+ let recvT = lowerer.mapTypeOf(lowerer.typeOf(access.expression)) ?? dynFallbackType(lowerer, access.expression, lowerer.typeOf(access.expression));
7193
7482
  // A dynamic-import promise under an unmappable checker type
7194
7483
  // (`Promise<typeof import("./m")>` — module-namespace types have no
7195
7484
  // static mapping): the BINDING holds the island promise
@@ -7242,6 +7531,8 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
7242
7531
  loc,
7243
7532
  };
7244
7533
  }
7534
+ if (receiver.type.kind === "dyn" && lowerer.dynConvertible(recvT))
7535
+ receiver = lowerer.coerceInto(access.expression, receiver, recvT);
7245
7536
  if (receiver.type.kind !== "promise") {
7246
7537
  // mapTypeOf said promise but the value lowered as something else —
7247
7538
  // a lowering gap, named rather than ICEd on.
@@ -7534,7 +7825,7 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
7534
7825
  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
7826
  }
7536
7827
  const param = cb.type.params[0];
7537
- if (param !== undefined && !typeEquals(param, inner)) {
7828
+ if (param !== undefined && !typeEquals(param, inner) && !(inner.kind === "void" && param.kind === "dyn")) {
7538
7829
  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
7830
  }
7540
7831
  const resultT = lowerer.mapTypeOf(lowerer.typeOf(call));
@@ -7568,6 +7859,8 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
7568
7859
  }
7569
7860
  else {
7570
7861
  body.push({ kind: "exprStmt", expr: awaitE, loc });
7862
+ if (param !== undefined)
7863
+ handlerArgs = [dynUndefinedExpr(loc)];
7571
7864
  }
7572
7865
  const handlerCall = {
7573
7866
  kind: "callValue",
@@ -8544,6 +8837,8 @@ function lowerObjectStaticCall(lowerer, call, access) {
8544
8837
  object = { kind: "dynFrom", value: object, type: DYN, loc: locOf(call),
8545
8838
  ...(fnName !== null ? { fnName } : {}) };
8546
8839
  }
8840
+ if (object.type.kind !== "dyn" && canConvertToDyn(object.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id)))
8841
+ object = lowerer.coerceInto(call.arguments[0], object, DYN);
8547
8842
  if (object.type.kind === "dyn") {
8548
8843
  const loc = locOf(call);
8549
8844
  if (member === "getPrototypeOf")
@@ -8600,7 +8895,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
8600
8895
  if (unitTest)
8601
8896
  return unitTest;
8602
8897
  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)");
8898
+ return { kind: "libCall", fn: "dyn.sameValue", args: [lowerer.coerceInto(leftNode, left, DYN), lowerer.coerceInto(rightNode, right, DYN)], type: BOOL, loc };
8604
8899
  }
8605
8900
  if (left.type.kind === "union" || right.type.kind === "union") {
8606
8901
  const ut = left.type.kind === "union" ? left.type : right.type;
@@ -8728,7 +9023,8 @@ function lowerObjectStaticCall(lowerer, call, access) {
8728
9023
  return prototype;
8729
9024
  if (isJsSourceFile(call.getSourceFile()) && call.arguments.length > 0 && !call.arguments.some(ts.isSpreadElement)) {
8730
9025
  const target = tryLowerExpression(lowerer, call.arguments[0]);
8731
- if (target?.type.kind === "func" && lowerer.dynConvertible(target.type)) {
9026
+ if (target && ((target.type.kind === "func" && lowerer.dynConvertible(target.type)) ||
9027
+ (target.type.kind === "object" && lowerer.errorHierarchyClassOf(target.type.className)))) {
8732
9028
  const loc = locOf(call);
8733
9029
  return { kind: "libCall", fn: "dyn.assignAll", args: [lowerer.coerceToExpected(target, DYN),
8734
9030
  { kind: "dynArrLit", elems: call.arguments.slice(1).map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc },
@@ -8904,6 +9200,14 @@ function lowerObjectStaticCall(lowerer, call, access) {
8904
9200
  if (call.arguments.some((a) => ts.isSpreadElement(a)))
8905
9201
  return null;
8906
9202
  let target = tryLowerExpression(lowerer, call.arguments[0]);
9203
+ const targetNode = call.arguments[0];
9204
+ // The checker gives C.prototype the instance type, but its lowered
9205
+ // value is the shared prototype table, not an instance to unbox.
9206
+ const prototypeTarget = ts.isPropertyAccessExpression(targetNode) && targetNode.name.text === "prototype" &&
9207
+ (exactClassOfReceiver(lowerer, targetNode.expression) !== null || storedClassValueType(lowerer, targetNode.expression)?.kind === "classval");
9208
+ const declaredTarget = target?.type.kind === "dyn" && !prototypeTarget && !isJsSourceFile(targetNode.getSourceFile()) ? lowerer.mapTypeOf(lowerer.typeOf(targetNode)) : null;
9209
+ if (target && declaredTarget && isDynTypedRefType(declaredTarget))
9210
+ target = lowerer.coerceToExpected(target, declaredTarget);
8907
9211
  if (target && member === "defineProperty") {
8908
9212
  const native = lowerClassDataDescriptor(lowerer, call, member, target);
8909
9213
  if (native)
@@ -8915,11 +9219,10 @@ function lowerObjectStaticCall(lowerer, call, access) {
8915
9219
  return descriptor;
8916
9220
  target = lowerer.coerceToExpected(target, DYN);
8917
9221
  }
8918
- // Error.cause owns a live data-property slot shared with its checked
8919
- // view. Other native fields do not yet synchronize descriptor edits.
9222
+ // Error instances share a live property table with their checked view.
8920
9223
  const keyNode = call.arguments[1];
8921
9224
  if (target?.type.kind === "object" && target.type.className !== "%DOMException" && lowerer.errorHierarchyClassOf(target.type.className) &&
8922
- ts.isStringLiteral(keyNode) && keyNode.text === "cause") {
9225
+ ((ts.isStringLiteral(keyNode) && (keyNode.text === "cause" || keyNode.text === "message")) || lowerer.mapTypeOf(lowerer.typeOf(keyNode))?.kind === "symbol")) {
8923
9226
  target = lowerer.coerceToExpected(target, DYN);
8924
9227
  }
8925
9228
  if (target?.type.kind === "func" && lowerer.dynConvertible(target.type)) {
@@ -9048,14 +9351,19 @@ function lowerObjectStaticCall(lowerer, call, access) {
9048
9351
  const recvNode = call.arguments[0];
9049
9352
  const keyNode = call.arguments[1];
9050
9353
  const probed = tryLowerExpression(lowerer, recvNode);
9354
+ const constructor = probed?.type.kind === "classval" ? lowerer.classes.get(probed.type.className) : undefined;
9051
9355
  // A CHECKED-DYNAMIC receiver (the JS file-scope object-literal
9052
9356
  // identity story): the runtime dyn probe — OBJ member presence, ARR
9053
9357
  // 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))) {
9358
+ if (probed?.type.kind === "dyn" || (probed && isDynTypedRefType(probed.type)) ||
9359
+ (probed?.type.kind === "object" && lowerer.errorHierarchyClassOf(probed.type.className)) ||
9360
+ (probed && constructor && (constructor.callableBase || hasRuntimeStatics(constructor))) ||
9361
+ (probed?.type.kind === "func" && lowerer.dynConvertible(probed.type))) {
9055
9362
  const loc = locOf(call);
9056
9363
  const receiver = lowerer.coerceToExpected(probed, DYN);
9057
9364
  const rawKey = lowerer.lowerExpr(keyNode);
9058
- if (rawKey.type.kind === "dyn" || rawKey.type.kind === "symbol")
9365
+ if (rawKey.type.kind === "dyn" || rawKey.type.kind === "symbol" ||
9366
+ rawKey.type.kind === "union" && lowerer.dynConvertible(rawKey.type))
9059
9367
  return {
9060
9368
  kind: "libCall", fn: "dyn.hasOwnComputed", args: [receiver, lowerer.coerceToExpected(rawKey, DYN)], type: BOOL, loc,
9061
9369
  };
@@ -9140,7 +9448,8 @@ function lowerObjectStaticCall(lowerer, call, access) {
9140
9448
  const isPrimitive = probed !== null && probed !== undefined &&
9141
9449
  (isUnitType(probed.type) || probed.type.kind === "string" ||
9142
9450
  probed.type.kind === "f64" || probed.type.kind === "bool");
9143
- if (isDyn || isPrimitive || isFunction || (probed && isDynTypedRefType(probed.type))) {
9451
+ const isJsUnion = probed?.type.kind === "union" && isJsSourceFile(call.getSourceFile()) && lowerer.dynConvertible(probed.type);
9452
+ if (isDyn || isPrimitive || isFunction || isJsUnion || (probed && isDynTypedRefType(probed.type))) {
9144
9453
  const fn = member === "keys" ? "dyn.objKeys" : member === "values" ? "dyn.objValues" : "dyn.objEntries";
9145
9454
  let v = lowerer.lowerExpr(argNode);
9146
9455
  if (v.type.kind !== "dyn")
@@ -9221,7 +9530,6 @@ function lowerObjectStaticCall(lowerer, call, access) {
9221
9530
  const recT = argIr;
9222
9531
  const ref = { kind: "varRef", localId: "r.0", type: recT, loc };
9223
9532
  const outRef = { kind: "varRef", localId: "out.0", type: resultT, loc };
9224
- lowerer.arrHofHelpers.set(key, helper);
9225
9533
  const fn = {
9226
9534
  name: helper,
9227
9535
  params: [{ localId: "r.0", name: "r", type: recT }],
@@ -9250,6 +9558,8 @@ function lowerObjectStaticCall(lowerer, call, access) {
9250
9558
  return null;
9251
9559
  if (typeEquals(vt, valueT))
9252
9560
  return value;
9561
+ if (valueT.kind === "dyn" && lowerer.dynConvertible(vt))
9562
+ return lowerer.coerceToExpected(value, DYN);
9253
9563
  if (valueT.kind === "union" && vt.kind !== "union") {
9254
9564
  const tag = lowerer.armTag(valueT.unionId, vt);
9255
9565
  if (tag >= 0) {
@@ -9269,7 +9579,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
9269
9579
  guardUndefTag = undefTag;
9270
9580
  const arms = lowerer.unions.get(f.type.unionId)?.arms ?? [];
9271
9581
  const others = arms.filter((a) => a.kind !== "undefinedT");
9272
- if (typeEquals(f.type, valueT ?? f.type)) {
9582
+ if (valueT?.kind === "dyn" || typeEquals(f.type, valueT ?? f.type)) {
9273
9583
  // The field union IS the result union (single-field shapes):
9274
9584
  // push the raw box — but then the undefined skip must NOT
9275
9585
  // narrow. Handled below via vt === valueT.
@@ -9293,7 +9603,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
9293
9603
  "cannot re-tag into the result element type — read the fields directly)");
9294
9604
  }
9295
9605
  }
9296
- else if (!typeEquals(f.type, valueT ?? f.type)) {
9606
+ else if (valueT?.kind !== "dyn" && !typeEquals(f.type, valueT ?? f.type)) {
9297
9607
  lowerer.unsupported("SC1090", call, `Object.${member} over '${lowerer.fmt(argIr)}' (field '${f.name}' is a union that cannot ` +
9298
9608
  "re-tag into the result element type — read the fields directly)");
9299
9609
  }
@@ -9333,6 +9643,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
9333
9643
  fn.body = body;
9334
9644
  };
9335
9645
  finalize();
9646
+ lowerer.arrHofHelpers.set(key, helper);
9336
9647
  lowerer.shapeOrderHelperFinalizers.push(finalize);
9337
9648
  lowerer.liftedFns.push(fn);
9338
9649
  }
@@ -9381,6 +9692,15 @@ export function lowerFunction(lowerer, decl) {
9381
9692
  params.push({ localId: argsLocal.id, name: "%arguments", type: DYN });
9382
9693
  ctx.argumentsLocal = argsLocal;
9383
9694
  }
9695
+ if (isJsSourceFile(decl.getSourceFile()) && sig.params.length === 1 &&
9696
+ sig.params[0]?.mode === "dynRest" && bodyReadsArguments(decl)) {
9697
+ const argsLocal = lowerer.declareHiddenLocal("%arguments", DYN);
9698
+ prologue.push({ kind: "varDecl", localId: argsLocal.id, init: {
9699
+ kind: "dynInvoke", recv: varRef(params[0].localId, DYN, locOf(decl)), method: "slice",
9700
+ calleeName: "Array.prototype.slice", args: [], type: DYN, loc: locOf(decl),
9701
+ }, loc: locOf(decl) });
9702
+ ctx.argumentsLocal = argsLocal;
9703
+ }
9384
9704
  const bodyBlock = blockBodyOf(decl);
9385
9705
  if (!bodyBlock) {
9386
9706
  lowerer.unsupported("SC1090", decl, "function declarations whose block body the frontend cannot locate");
@@ -10404,6 +10724,14 @@ function lowerObjLitGenericMethodCall(lowerer, call, access) {
10404
10724
  const propSym = lowerer.checker.getPropertyOfType(recvT, name);
10405
10725
  if (!propSym)
10406
10726
  return null;
10727
+ const propertyDecl = lowerer.checker.valueDeclarationOf(propSym);
10728
+ if (propertyDecl && ts.isShorthandPropertyAssignment(propertyDecl) && ts.isIdentifier(propertyDecl.name) && ts.isObjectLiteralExpression(propertyDecl.parent)) {
10729
+ requireObjLitGenericReceiver(lowerer, call, access.expression, propertyDecl.parent, name);
10730
+ const targetSymbol = lowerer.checker.getShorthandAssignmentValueSymbol(propertyDecl);
10731
+ const target = targetSymbol ? lowerer.genericFnsBySymbol.get((targetSymbol.flags & ts.SymbolFlags.Alias ? lowerer.checker.getAliasedSymbol(targetSymbol) : targetSymbol)) : undefined;
10732
+ if (target)
10733
+ return lowerer.lowerGenericCall(call, target);
10734
+ }
10407
10735
  if (!isGenericCallableMemberType(lowerer.checker.getTypeOfSymbol(propSym), lowerer.checker))
10408
10736
  return null;
10409
10737
  // CLASS members belong to the class path (lowerClassGenericMethodCall
@@ -10502,6 +10830,12 @@ export function lowerObjectMethodCall(lowerer, call, access) {
10502
10830
  lowerUnionObjectDynFieldCall(lowerer, call, access, mappedReceiver);
10503
10831
  if (dispatched)
10504
10832
  return dispatched;
10833
+ const arms = lowerer.unions.get(mappedReceiver.unionId)?.arms;
10834
+ if (isJsSourceFile(call.getSourceFile()) && arms?.every((arm) => arm.kind === "object" &&
10835
+ !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);
10838
+ }
10505
10839
  }
10506
10840
  const receiverIr = mappedReceiver?.kind === "object"
10507
10841
  ? mappedReceiver
@@ -10614,6 +10948,21 @@ export function lowerObjectMethodCall(lowerer, call, access) {
10614
10948
  return finish({ kind: "dynCall", callee, receiver, calleeName: access.getText(), args, type: DYN, loc });
10615
10949
  }
10616
10950
  }
10951
+ if (!fieldType && isJsSourceFile(call.getSourceFile()) && !info.def.runtime && !info.builtinError && !info.builtinEmitter && !info.builtinStream) {
10952
+ const loc = locOf(call);
10953
+ const value = lowerReceiver();
10954
+ const local = lowerer.declareHiddenLocal("%callReceiver", value.type);
10955
+ const reference = { kind: "varRef", localId: local.id, type: value.type, loc };
10956
+ const receiver = lowerer.coerceToExpected(reference, DYN);
10957
+ const callee = { kind: "dynKeyGet", value: receiver,
10958
+ key: { kind: "strLit", value: access.name.text, type: STRING, loc }, type: DYN, loc };
10959
+ const spread = call.arguments.some(ts.isSpreadElement) ? lowerSpreadArgsCall(lowerer, call, callee, loc) : null;
10960
+ if (spread && spread.kind !== "dynCall")
10961
+ lowerer.unsupported("SC1090", call, "native property call spread arguments");
10962
+ const result = spread !== null ? { ...spread, receiver } : { kind: "dynCall", callee, receiver,
10963
+ calleeName: access.getText(), args: call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
10964
+ return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id, init: value, loc }], result, type: DYN, loc };
10965
+ }
10617
10966
  return null;
10618
10967
  }
10619
10968
  if (!info || !found)
@@ -10696,6 +11045,22 @@ function lowerUnionObjectMethodCall(lowerer, call, access, receiverT) {
10696
11045
  plans.push({ arm, info, found });
10697
11046
  }
10698
11047
  const shapes = plans[0].found.sig.params;
11048
+ if (plans.some((plan) => isClassCallback(lowerer, plan.info, method))) {
11049
+ const loc = locOf(call);
11050
+ const local = lowerer.declareHiddenLocal("%unionMethodReceiver", DYN);
11051
+ const receiver = varRef(local.id, DYN, loc);
11052
+ const callee = { kind: "dynKeyGet", value: receiver,
11053
+ key: { kind: "strLit", value: method, type: STRING, loc }, type: DYN, loc };
11054
+ const spread = call.arguments.some(ts.isSpreadElement) ? lowerSpreadArgsCall(lowerer, call, callee, loc) : null;
11055
+ if (spread && spread.kind !== "dynCall")
11056
+ lowerer.unsupported("SC1090", call, "union method spread arguments");
11057
+ const value = spread !== null ? { ...spread, receiver } : { kind: "dynCall", callee, receiver,
11058
+ calleeName: access.getText(), args: call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
11059
+ const resultT = lowerer.mapTypeOf(lowerer.typeOf(call));
11060
+ const result = resultT && !isUnitType(resultT) ? lowerer.coerceToExpected(value, resultT) : value;
11061
+ return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id,
11062
+ init: lowerer.coerceInto(access.expression, lowerer.lowerExpr(access.expression), DYN), loc }], result, type: result.type, loc };
11063
+ }
10699
11064
  if (!plans.every((plan) => paramAbisEqual(shapes, plan.found.sig.params)))
10700
11065
  return null;
10701
11066
  const resultT = lowerer.mapTypeOf(lowerer.typeOf(call));