@scriptc/compiler 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +45 -17
  2. package/ambient/scriptc.d.ts +2 -1
  3. package/dist/backend/build-cache.js.map +1 -1
  4. package/dist/backend/c/async.js +24 -2
  5. package/dist/backend/c/async.js.map +1 -1
  6. package/dist/backend/c/c-emitter.d.ts +22 -10
  7. package/dist/backend/c/c-emitter.js +60 -15
  8. package/dist/backend/c/c-emitter.js.map +1 -1
  9. package/dist/backend/c/exprs.js +220 -10
  10. package/dist/backend/c/exprs.js.map +1 -1
  11. package/dist/backend/c/island.js.map +1 -1
  12. package/dist/backend/c/may-throw.js.map +1 -1
  13. package/dist/backend/c/stmts.d.ts +3 -5
  14. package/dist/backend/c/stmts.js +58 -17
  15. package/dist/backend/c/stmts.js.map +1 -1
  16. package/dist/backend/c/types.js.map +1 -1
  17. package/dist/backend/c/walkers.js +31 -5
  18. package/dist/backend/c/walkers.js.map +1 -1
  19. package/dist/backend/external-c.js.map +1 -1
  20. package/dist/backend/linker.js.map +1 -1
  21. package/dist/backend/llvm/blocks.js.map +1 -1
  22. package/dist/backend/llvm/dyn.js +56 -3
  23. package/dist/backend/llvm/dyn.js.map +1 -1
  24. package/dist/backend/llvm/emitter.js +98 -19
  25. package/dist/backend/llvm/emitter.js.map +1 -1
  26. package/dist/backend/llvm/expr-async.js +85 -3
  27. package/dist/backend/llvm/expr-async.js.map +1 -1
  28. package/dist/backend/llvm/expr-bytes.js.map +1 -1
  29. package/dist/backend/llvm/expr-calls.js.map +1 -1
  30. package/dist/backend/llvm/expr-containers.js.map +1 -1
  31. package/dist/backend/llvm/expr-context.d.ts +1 -0
  32. package/dist/backend/llvm/expr-control.js.map +1 -1
  33. package/dist/backend/llvm/expr-dispatch.js.map +1 -1
  34. package/dist/backend/llvm/expr-dynamic.js +6 -3
  35. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  36. package/dist/backend/llvm/expr-island.js.map +1 -1
  37. package/dist/backend/llvm/expr-primitives.js.map +1 -1
  38. package/dist/backend/llvm/expr-records.js.map +1 -1
  39. package/dist/backend/llvm/expr-stream-bridges.js +220 -9
  40. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  41. package/dist/backend/llvm/lib-dispatch.js +2 -0
  42. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  43. package/dist/backend/llvm/lib-shared.js +18 -0
  44. package/dist/backend/llvm/lib-shared.js.map +1 -1
  45. package/dist/backend/llvm/lib-stream.js +6 -3
  46. package/dist/backend/llvm/lib-stream.js.map +1 -1
  47. package/dist/backend/llvm/split.js.map +1 -1
  48. package/dist/backend/llvm/unsupported.js.map +1 -1
  49. package/dist/backend/llvm/walkers.js.map +1 -1
  50. package/dist/backend/native-codegen.js.map +1 -1
  51. package/dist/backend/native-codegen.test.js +2 -0
  52. package/dist/backend/native-codegen.test.js.map +1 -1
  53. package/dist/backend/native-toolchain.js.map +1 -1
  54. package/dist/backend/native-toolchain.test.js.map +1 -1
  55. package/dist/backend/runtime-pack.js.map +1 -1
  56. package/dist/backend/targets.js.map +1 -1
  57. package/dist/backend/vendor-archives.js.map +1 -1
  58. package/dist/compat/fetch-profile.js +4 -2
  59. package/dist/compat/fetch-profile.js.map +1 -1
  60. package/dist/coverage/report.js.map +1 -1
  61. package/dist/coverage/surface-manifest.js +12 -0
  62. package/dist/coverage/surface-manifest.js.map +1 -1
  63. package/dist/diagnostics/diagnostic.d.ts +6 -5
  64. package/dist/diagnostics/diagnostic.js +7 -6
  65. package/dist/diagnostics/diagnostic.js.map +1 -1
  66. package/dist/diagnostics/render.js.map +1 -1
  67. package/dist/ffi/ffi-manifest.js.map +1 -1
  68. package/dist/frontend/cjs-lexer.js.map +1 -1
  69. package/dist/frontend/dts-paths.js.map +1 -1
  70. package/dist/frontend/input-tracker.d.ts +10 -0
  71. package/dist/frontend/input-tracker.js +26 -3
  72. package/dist/frontend/input-tracker.js.map +1 -1
  73. package/dist/frontend/input-tracker.test.js +8 -1
  74. package/dist/frontend/input-tracker.test.js.map +1 -1
  75. package/dist/frontend/lib-contract.js.map +1 -1
  76. package/dist/frontend/lowering/array-values.d.ts +4 -0
  77. package/dist/frontend/lowering/array-values.js +18 -2
  78. package/dist/frontend/lowering/array-values.js.map +1 -1
  79. package/dist/frontend/lowering/callback-arg.js.map +1 -1
  80. package/dist/frontend/lowering/containers/bytes.d.ts +35 -0
  81. package/dist/frontend/lowering/containers/bytes.js +1021 -0
  82. package/dist/frontend/lowering/containers/bytes.js.map +1 -0
  83. package/dist/frontend/lowering/containers/string-and-regexp.d.ts +17 -0
  84. package/dist/frontend/lowering/containers/string-and-regexp.js +345 -0
  85. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -0
  86. package/dist/frontend/lowering/expressions/evaluation-safety.d.ts +13 -0
  87. package/dist/frontend/lowering/expressions/evaluation-safety.js +76 -0
  88. package/dist/frontend/lowering/expressions/evaluation-safety.js.map +1 -0
  89. package/dist/frontend/lowering/expressions/object-literals.d.ts +44 -0
  90. package/dist/frontend/lowering/expressions/object-literals.js +1815 -0
  91. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -0
  92. package/dist/frontend/lowering/expressions/optional-chains.d.ts +31 -0
  93. package/dist/frontend/lowering/expressions/optional-chains.js +382 -0
  94. package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -0
  95. package/dist/frontend/lowering/expressions/try-lower-expression.d.ts +7 -0
  96. package/dist/frontend/lowering/expressions/try-lower-expression.js +26 -0
  97. package/dist/frontend/lowering/expressions/try-lower-expression.js.map +1 -0
  98. package/dist/frontend/lowering/lib-boundary.js +7 -2
  99. package/dist/frontend/lowering/lib-boundary.js.map +1 -1
  100. package/dist/frontend/lowering/lower-assert.js.map +1 -1
  101. package/dist/frontend/lowering/lower-async-iteration.d.ts +7 -0
  102. package/dist/frontend/lowering/lower-async-iteration.js +657 -0
  103. package/dist/frontend/lowering/lower-async-iteration.js.map +1 -0
  104. package/dist/frontend/lowering/lower-builtins.d.ts +18 -0
  105. package/dist/frontend/lowering/lower-builtins.js +219 -48
  106. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  107. package/dist/frontend/lowering/lower-calls.d.ts +13 -4
  108. package/dist/frontend/lowering/lower-calls.js +407 -64
  109. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  110. package/dist/frontend/lowering/lower-classes.d.ts +7 -13
  111. package/dist/frontend/lowering/lower-classes.js +128 -35
  112. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  113. package/dist/frontend/lowering/lower-comptime.js.map +1 -1
  114. package/dist/frontend/lowering/lower-containers.d.ts +1 -47
  115. package/dist/frontend/lowering/lower-containers.js +135 -1467
  116. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  117. package/dist/frontend/lowering/lower-event-emitter.js +51 -5
  118. package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
  119. package/dist/frontend/lowering/lower-exprs.d.ts +0 -78
  120. package/dist/frontend/lowering/lower-exprs.js +402 -2351
  121. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  122. package/dist/frontend/lowering/lower-generators.d.ts +18 -3
  123. package/dist/frontend/lowering/lower-generators.js +145 -9
  124. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  125. package/dist/frontend/lowering/lower-inspect.js +3 -3
  126. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  127. package/dist/frontend/lowering/lower-island.d.ts +6 -0
  128. package/dist/frontend/lowering/lower-island.js +37 -5
  129. package/dist/frontend/lowering/lower-island.js.map +1 -1
  130. package/dist/frontend/lowering/lower-modules.js +52 -15
  131. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  132. package/dist/frontend/lowering/lower-node-module.d.ts +18 -0
  133. package/dist/frontend/lowering/lower-node-module.js +302 -0
  134. package/dist/frontend/lowering/lower-node-module.js.map +1 -0
  135. package/dist/frontend/lowering/lower-server.js +1 -1
  136. package/dist/frontend/lowering/lower-server.js.map +1 -1
  137. package/dist/frontend/lowering/lower-stmts.d.ts +5 -24
  138. package/dist/frontend/lowering/lower-stmts.js +519 -253
  139. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  140. package/dist/frontend/lowering/lower-stream.js +4 -4
  141. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  142. package/dist/frontend/lowering/lowerer.d.ts +37 -34
  143. package/dist/frontend/lowering/lowerer.js +143 -57
  144. package/dist/frontend/lowering/lowerer.js.map +1 -1
  145. package/dist/frontend/lowering/optional-arguments.d.ts +9 -0
  146. package/dist/frontend/lowering/optional-arguments.js +57 -0
  147. package/dist/frontend/lowering/optional-arguments.js.map +1 -0
  148. package/dist/frontend/npm-static-declarations.d.ts +35 -0
  149. package/dist/frontend/npm-static-declarations.js +506 -0
  150. package/dist/frontend/npm-static-declarations.js.map +1 -0
  151. package/dist/frontend/npm-static-declarations.test.d.ts +1 -0
  152. package/dist/frontend/npm-static-declarations.test.js +122 -0
  153. package/dist/frontend/npm-static-declarations.test.js.map +1 -0
  154. package/dist/frontend/npm-static.d.ts +2 -0
  155. package/dist/frontend/npm-static.js +26 -10
  156. package/dist/frontend/npm-static.js.map +1 -1
  157. package/dist/frontend/npm.d.ts +60 -0
  158. package/dist/frontend/npm.js +38 -4
  159. package/dist/frontend/npm.js.map +1 -1
  160. package/dist/frontend/npm.test.d.ts +1 -0
  161. package/dist/frontend/npm.test.js +50 -0
  162. package/dist/frontend/npm.test.js.map +1 -0
  163. package/dist/frontend/program.d.ts +3 -2
  164. package/dist/frontend/program.js +495 -68
  165. package/dist/frontend/program.js.map +1 -1
  166. package/dist/frontend/resolve.d.ts +10 -2
  167. package/dist/frontend/resolve.js +90 -14
  168. package/dist/frontend/resolve.js.map +1 -1
  169. package/dist/frontend/resolve.test.js +4 -1
  170. package/dist/frontend/resolve.test.js.map +1 -1
  171. package/dist/frontend/runtime-resolve.d.ts +22 -0
  172. package/dist/frontend/runtime-resolve.js +101 -0
  173. package/dist/frontend/runtime-resolve.js.map +1 -0
  174. package/dist/frontend/runtime-resolve.test.d.ts +1 -0
  175. package/dist/frontend/runtime-resolve.test.js +18 -0
  176. package/dist/frontend/runtime-resolve.test.js.map +1 -0
  177. package/dist/frontend/ts7/adapter.js +12 -13
  178. package/dist/frontend/ts7/adapter.js.map +1 -1
  179. package/dist/frontend/ts7/ast.js.map +1 -1
  180. package/dist/frontend/ts7/census-check.js +3 -3
  181. package/dist/frontend/ts7/census-check.js.map +1 -1
  182. package/dist/frontend/ts7/checker.d.ts +3 -0
  183. package/dist/frontend/ts7/checker.js +12 -3
  184. package/dist/frontend/ts7/checker.js.map +1 -1
  185. package/dist/frontend/ts7/enums.js.map +1 -1
  186. package/dist/frontend/ts7/program-adapter.js +42 -3
  187. package/dist/frontend/ts7/program-adapter.js.map +1 -1
  188. package/dist/frontend/type-mapper.js +120 -7
  189. package/dist/frontend/type-mapper.js.map +1 -1
  190. package/dist/index.js +5 -5
  191. package/dist/index.js.map +1 -1
  192. package/dist/ir/analysis.js.map +1 -1
  193. package/dist/ir/ir.d.ts +60 -30
  194. package/dist/ir/ir.js +57 -6
  195. package/dist/ir/ir.js.map +1 -1
  196. package/dist/ir/validate.js +44 -59
  197. package/dist/ir/validate.js.map +1 -1
  198. package/dist/library/cache-primitives.js.map +1 -1
  199. package/dist/library/cache-reset.test.js.map +1 -1
  200. package/dist/library/compiler-self-identity.js.map +1 -1
  201. package/dist/library/int-infer.js.map +1 -1
  202. package/dist/library/int-infer.test.js.map +1 -1
  203. package/dist/library/library-profile.js.map +1 -1
  204. package/dist/library/sidecar-validate.js.map +1 -1
  205. package/dist/library/sidecar.js.map +1 -1
  206. package/dist/startup-cache.js.map +1 -1
  207. package/dist/wasi-paths.js.map +1 -1
  208. package/package.json +18 -18
  209. package/surface-manifest.json +60 -4
@@ -1,3 +1,4 @@
1
+ import { InternalCompilerError } from "../../errors.js";
1
2
  /* Call lowering: the lowerCall dispatch chain, parameter-shape analysis and
2
3
  * argument completion (optional/default/rest, explicit-undefined ≡ omission),
3
4
  * function/lambda lowering and signature collection, and monomorphizing
@@ -6,15 +7,19 @@ import * as ts from "../ts7/adapter.js";
6
7
  import { lowerGenMethodCall } from "./lower-generators.js";
7
8
  import { BOOL, CAUGHT, DYN, F64, JSVAL, STRING, SYMBOL_T, UNDEFINED_T, VOID, arrayOf, canBoxFuncIntoDyn, canConvertToDyn, canDynCheckTo, canMarshalTypedFuncIntoIsland, ffiClassType, ffiSourceParamTypes, funcOf, isFfiCallbackParam, isFfiContextParam, isFfiReleaseParam, isUnitType, shapeHasAccessorSlots, typeEquals } from "../../ir/ir.js";
8
9
  import { isJsSourceFile, locOf } from "../program.js";
9
- import { isGenericCallableMemberType, typeKey } from "../type-mapper.js";
10
+ import { genResultRecord, isGenericCallableMemberType, typeKey } from "../type-mapper.js";
10
11
  import { PoisonError, dynFallbackType, dynUndefinedExpr, importCallHandleType, jsFuncNameOf, newFnCtx, nodeThrowExpr } from "./lowerer.js";
11
12
  import { enforceLibBoundary } from "./lib-boundary.js";
12
13
  import { NARROW_FIRST, builtinFenceHintOf, builtinModuleFnOf } from "./surfaces.js";
13
14
  import { ffiBindingDiag, ffiSignatureDiag, libCallbackDiag, requiresDynamicDiag } from "../../diagnostics/diagnostic.js";
14
15
  import { mixinFnShapeOf } from "./lower-mixins.js";
15
- import { bufEncoding, dynStringReceiver, lowerArrayFromCall, lowerDynArrayFilterCall, lowerDynArrayFlatMapCall, lowerGroupByStaticCall, lowerIteratorHelperCall, lowerObjectAssignIndexShape, lowerObjectFromEntriesCall, lowerObjectIterOverIndexShape, lowerRegexMethodCall, lowerStringMethodCall, lowerTupleReadMethodCall } from "./lower-containers.js";
16
- import { lowerChildStreamMethodCall, lowerCreateRequireCall, lowerDirentMethodCall, lowerFileHandleMethodCall, lowerPerfHooksCall, lowerProcStreamMethodCall, lowerReflectApplyCall, lowerWatcherMethodCall } from "./lower-builtins.js";
17
- import { droppableStatic, lowerAbsenceProbe, lowerPromiseAllTupleCall, lowerPromiseRejectCall, probeLower, templateRawTextOf } from "./lower-exprs.js";
16
+ import { dynStringReceiver, lowerArrayFromCall, lowerDynArrayFilterCall, lowerDynArrayFlatMapCall, lowerGroupByStaticCall, lowerIteratorHelperCall, lowerObjectAssignIndexShape, lowerObjectFromEntriesCall, lowerObjectIterOverIndexShape, lowerTupleReadMethodCall } from "./lower-containers.js";
17
+ import { bufEncoding } from "./containers/bytes.js";
18
+ import { lowerRegexMethodCall, lowerStringMethodCall } from "./containers/string-and-regexp.js";
19
+ import { lowerChildStreamMethodCall, lowerCreateRequireCall, lowerDirentMethodCall, lowerFileHandleMethodCall, lowerImportMetaResolveCall, lowerPerfHooksCall, lowerProcStreamMethodCall, lowerReflectApplyCall, lowerRequireResolveCall, lowerWatcherMethodCall } from "./lower-builtins.js";
20
+ import { lowerAbsenceProbe, lowerPromiseAllTupleCall, lowerPromiseRejectCall, templateRawTextOf } from "./lower-exprs.js";
21
+ import { isSafeToDiscard } from "./expressions/evaluation-safety.js";
22
+ import { tryLowerExpression } from "./expressions/try-lower-expression.js";
18
23
  import { httpClientFnBindingOf, isStreamUndefCallExpr, lowerCompatReqStreamOptionalCall, lowerHttpClientFnCall } from "./lower-server.js";
19
24
  import { EMITTER_API_MEMBERS, exactInstanceClassOf, findGenericMethodOn, lowerClassGenericMethodCall, lowerStaticMethodCall } from "./lower-classes.js";
20
25
  import { emitterRooted, lowerEmitterMethodCall } from "./lower-event-emitter.js";
@@ -26,6 +31,14 @@ import { expandoMemberRead } from "./lower-expando.js";
26
31
  import { npmStaticPackageOfPath } from "../npm-static.js";
27
32
  import { countedFor, varRef } from "../../ir/build.js";
28
33
  import { rejectStaticThis } from "./static-this.js";
34
+ import { fenceNodeModuleMutationCall, lowerRequireCacheKeys } from "./lower-node-module.js";
35
+ export function generatorMeta(lowerer, type) {
36
+ const resultType = genResultRecord(type.yieldT, type.retT, lowerer.shapes, lowerer.unions);
37
+ if (resultType === null) {
38
+ throw new InternalCompilerError("lowerer bug: mapped generator without an IteratorResult record");
39
+ }
40
+ return { yieldT: type.yieldT, nextT: type.nextT, resultType };
41
+ }
29
42
  /** Instantiation cap per generic function: same-key recursion (`len<T>`
30
43
  * calling itself) converges, but POLYMORPHIC recursion (`f<T>` calling
31
44
  * `f<T[]>`) would request new instances forever — the cap turns that into a
@@ -585,6 +598,16 @@ export function appendImplicitUndefinedReturn(lowerer, body, bodyReturn, loc) {
585
598
  /** A declaration's checker-derived IR return type. The unmappable-type
586
599
  * diagnostic points at `blame` (the name for top-level declarations, the
587
600
  * whole node for lambda-likes — preserving each caller's historical loc). */
601
+ function hasExplicitJsDocReturn(decl) {
602
+ const sourceFile = decl.getSourceFile();
603
+ return /@returns?\b/.test(sourceFile.text.slice(decl.pos, decl.getStart(sourceFile)));
604
+ }
605
+ function promiseCarriesDyn(lowerer, type) {
606
+ if (type.kind === "promise")
607
+ return type.inner.kind === "dyn";
608
+ return type.kind === "union" &&
609
+ (lowerer.unions.get(type.unionId)?.arms.some((arm) => promiseCarriesDyn(lowerer, arm)) ?? false);
610
+ }
588
611
  export function declaredReturnType(lowerer, decl, blame) {
589
612
  const sig = lowerer.checker.getSignatureFromDeclaration(decl);
590
613
  if (!sig)
@@ -596,6 +619,17 @@ export function declaredReturnType(lowerer, decl, blame) {
596
619
  // (`.action(() => { throw ... })`). `never` VALUES stay unmapped.
597
620
  if (retTsType.flags & ts.TypeFlags.Never)
598
621
  return VOID;
622
+ const mappedReturn = lowerer.mapTypeOf(retTsType);
623
+ if (isJsSourceFile(decl.getSourceFile()) &&
624
+ !hasExplicitJsDocReturn(decl) &&
625
+ mappedReturn !== null &&
626
+ promiseCarriesDyn(lowerer, mappedReturn) &&
627
+ decl.parameters.some((param) => {
628
+ const mapped = lowerer.mapTypeOf(lowerer.typeOf(param.name));
629
+ return mapped === null || mapped.kind === "dyn";
630
+ })) {
631
+ return DYN;
632
+ }
599
633
  // A JS function whose UNANNOTATED return infers a FUNCTION type
600
634
  // (test/common's mustCall — tsc infers `() => any` from the wrapper
601
635
  // it returns): the inferred arity is the wrapper's spelling, not a
@@ -691,9 +725,6 @@ export function collectSignatureInner(lowerer, decl) {
691
725
  return;
692
726
  const isAsync = decl.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) === true;
693
727
  const isGenerator = decl.asteriskToken !== undefined;
694
- if (isGenerator && isAsync) {
695
- lowerer.unsupported("SC1071", decl, "async generators (async function*)");
696
- }
697
728
  if (decl.typeParameters) {
698
729
  // Generic async composes: each monomorphized instance is an async
699
730
  // IrFunction like any other — its own spawn wrapper, its body
@@ -742,10 +773,11 @@ export function collectSignatureInner(lowerer, decl) {
742
773
  }
743
774
  const nameBlame = decl.name ?? decl;
744
775
  const returnType = lowerer.declaredReturnType(decl, nameBlame);
745
- if (isAsync && returnType.kind !== "promise") {
776
+ if (isAsync && !isGenerator && returnType.kind !== "promise") {
746
777
  lowerer.badType(nameBlame, lowerer.typeOf(nameBlame));
747
778
  }
748
- if (isGenerator && returnType.kind !== "generator") {
779
+ if (isGenerator &&
780
+ (returnType.kind !== "generator" || (returnType.async === true) !== isAsync)) {
749
781
  lowerer.badType(nameBlame, lowerer.typeOf(nameBlame));
750
782
  }
751
783
  const symbol = declSymbolOf(lowerer, decl);
@@ -761,7 +793,7 @@ export function collectSignatureInner(lowerer, decl) {
761
793
  returnType,
762
794
  isAsync,
763
795
  ...(isGenerator && returnType.kind === "generator"
764
- ? { generator: { yieldT: returnType.yieldT, nextT: returnType.nextT } }
796
+ ? { generator: generatorMeta(lowerer, returnType) }
765
797
  : {}),
766
798
  });
767
799
  }
@@ -1172,17 +1204,15 @@ export function lowerGenericInstance(lowerer, info, inst) {
1172
1204
  // and awaits park this instance's fibers.
1173
1205
  const isAsync = decl.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) === true;
1174
1206
  const nameBlame = (ts.isArrowFunction(decl) ? undefined : decl.name) ?? decl;
1175
- if (isAsync && inst.returnType.kind !== "promise") {
1207
+ const isGenerator = decl.asteriskToken !== undefined;
1208
+ if (isAsync && !isGenerator && inst.returnType.kind !== "promise") {
1176
1209
  lowerer.badType(nameBlame, lowerer.checker.getTypeAtLocation(nameBlame));
1177
1210
  }
1178
1211
  // A generic GENERATOR instance mirrors async: the body returns the
1179
1212
  // resolved TReturn channel, calls enter through the instance's own
1180
1213
  // gen-spawn wrapper (the emitter routes by fn.generator).
1181
- const isGenerator = decl.asteriskToken !== undefined;
1182
- if (isGenerator && isAsync) {
1183
- lowerer.unsupported("SC1071", decl, "async generators (async function*)");
1184
- }
1185
- if (isGenerator && inst.returnType.kind !== "generator") {
1214
+ if (isGenerator &&
1215
+ (inst.returnType.kind !== "generator" || (inst.returnType.async === true) !== isAsync)) {
1186
1216
  lowerer.badType(nameBlame, lowerer.checker.getTypeAtLocation(nameBlame));
1187
1217
  }
1188
1218
  let bodyReturn = isGenerator
@@ -1198,7 +1228,7 @@ export function lowerGenericInstance(lowerer, info, inst) {
1198
1228
  if (cls && info.member.kind === "method")
1199
1229
  lowerer.currentClass = cls;
1200
1230
  if (isGenerator && inst.returnType.kind === "generator") {
1201
- fnCtx.generator = { yieldT: inst.returnType.yieldT, nextT: inst.returnType.nextT };
1231
+ fnCtx.generator = generatorMeta(lowerer, inst.returnType);
1202
1232
  }
1203
1233
  lowerer.fnStack.push(fnCtx);
1204
1234
  try {
@@ -1623,6 +1653,15 @@ function paramWrittenInBody(lowerer, body, sym, name) {
1623
1653
  walk(body);
1624
1654
  return written;
1625
1655
  }
1656
+ function broadPromiseParam(lowerer, type) {
1657
+ const mapped = lowerer.mapTypeOf(type);
1658
+ const arms = mapped?.kind === "union"
1659
+ ? lowerer.unions.get(mapped.unionId)?.arms
1660
+ : mapped === null ? undefined : [mapped];
1661
+ return !!arms &&
1662
+ arms.some((arm) => arm.kind === "promise" && arm.inner.kind === "dyn") &&
1663
+ arms.every((arm) => isUnitType(arm) || (arm.kind === "promise" && arm.inner.kind === "dyn"));
1664
+ }
1626
1665
  /** The implicit-type-parameter slots of a JS function-like: parallel to
1627
1666
  * decl.parameters, the param SYMBOL where the slot is a bindable
1628
1667
  * implicit-any param (identifier-named, no annotation/JSDoc type, not
@@ -1651,7 +1690,10 @@ export function implicitAnyParamSymbolsOf(lowerer, decl) {
1651
1690
  if (param.name.text === "this")
1652
1691
  return null;
1653
1692
  const t = lowerer.typeOf(param.name);
1654
- if ((t.flags & ts.TypeFlags.Any) === 0)
1693
+ const broadFunction = lowerer.checker.typeToString(t) === "Function";
1694
+ const broadArray = lowerer.checkerAnyArrayType(t);
1695
+ const broadPromise = broadPromiseParam(lowerer, t);
1696
+ if ((t.flags & ts.TypeFlags.Any) === 0 && !broadFunction && !broadArray && !broadPromise)
1655
1697
  return null;
1656
1698
  const sym = lowerer.checker.getSymbolAtLocation(param.name);
1657
1699
  if (!sym)
@@ -1670,13 +1712,54 @@ export function implicitAnyParamSymbolsOf(lowerer, decl) {
1670
1712
  * selects return INFERENCE with DYN as the recursion pin. */
1671
1713
  function implicitDeclaredReturn(lowerer, info) {
1672
1714
  try {
1715
+ const broadCallbackSymbols = new Set(info.decl.parameters.flatMap((param, index) => {
1716
+ const symbol = info.implicitParams?.[index];
1717
+ return symbol !== null && symbol !== undefined &&
1718
+ lowerer.checker.typeToString(lowerer.typeOf(param.name)) === "Function"
1719
+ ? [symbol]
1720
+ : [];
1721
+ }));
1722
+ let returnsBroadCallback = false;
1723
+ if (broadCallbackSymbols.size > 0 && info.decl.body !== undefined) {
1724
+ ts.walkPreorder(info.decl.body, (node) => {
1725
+ if (node !== info.decl.body && ts.isFunctionLike(node))
1726
+ return "skip";
1727
+ if (!ts.isReturnStatement(node) || node.expression === undefined)
1728
+ return undefined;
1729
+ let expression = node.expression;
1730
+ while (ts.isParenthesizedExpression(expression))
1731
+ expression = expression.expression;
1732
+ if (ts.isCallExpression(expression) &&
1733
+ ts.isIdentifier(expression.expression) &&
1734
+ broadCallbackSymbols.has(lowerer.checker.getSymbolAtLocation(expression.expression) ?? {})) {
1735
+ returnsBroadCallback = true;
1736
+ return "stop";
1737
+ }
1738
+ return undefined;
1739
+ });
1740
+ }
1741
+ if (returnsBroadCallback)
1742
+ return null;
1673
1743
  const declSig = lowerer.checker.getSignatureFromDeclaration(info.decl);
1674
1744
  if (!declSig)
1675
1745
  return null;
1676
1746
  const retTs = lowerer.checker.getReturnTypeOfSignature(declSig);
1677
1747
  if (retTs.flags & ts.TypeFlags.Any)
1678
1748
  return null;
1679
- return lowerer.mapTypeOf(retTs);
1749
+ if (lowerer.checker.isArrayType(retTs)) {
1750
+ const elem = lowerer.checker.getTypeArguments(retTs)[0];
1751
+ // An implicit-any parameter poisons an inferred array result to
1752
+ // any[] even when this instance's body produces one concrete
1753
+ // element type (`knownBy(cmd)` in commander). Let the existing
1754
+ // lowered-return unifier recover that type. Explicit unknown[]
1755
+ // remains a declared checked-dynamic contract and stays pinned.
1756
+ if (elem && (elem.flags & ts.TypeFlags.Any) !== 0)
1757
+ return null;
1758
+ }
1759
+ const mapped = lowerer.mapTypeOf(retTs);
1760
+ if (mapped !== null && promiseCarriesDyn(lowerer, mapped) && !hasExplicitJsDocReturn(info.decl))
1761
+ return null;
1762
+ return mapped;
1680
1763
  }
1681
1764
  catch (e) {
1682
1765
  if (!(e instanceof PoisonError))
@@ -1684,6 +1767,19 @@ function implicitDeclaredReturn(lowerer, info) {
1684
1767
  return null;
1685
1768
  }
1686
1769
  }
1770
+ /** True when a `this.method(...)` call targets an implicit npm-static
1771
+ * method whose result is settled from its lowered body rather than the
1772
+ * checker declaration. Uninitialized-local inference uses this to avoid
1773
+ * freezing an evolving `any` slot to stale JSDoc. */
1774
+ export function implicitMethodCallInfersReturn(lowerer, call) {
1775
+ if (!ts.isPropertyAccessExpression(call.expression) ||
1776
+ call.expression.expression.kind !== ts.SyntaxKind.ThisKeyword ||
1777
+ lowerer.currentClass === null) {
1778
+ return false;
1779
+ }
1780
+ const found = findGenericMethodOn(lowerer, lowerer.currentClass, call.expression.name.text);
1781
+ return found?.info.implicitParams !== undefined && implicitDeclaredReturn(lowerer, found.info) === null;
1782
+ }
1687
1783
  /** True when an IR type may BIND an implicit param (a concrete static
1688
1784
  * type — the checked-dynamic kinds keep the dyn slot, units have no
1689
1785
  * standalone representation). */
@@ -1709,15 +1805,37 @@ export function implicitCallInstance(lowerer, call, info) {
1709
1805
  return;
1710
1806
  }
1711
1807
  let bound = DYN;
1808
+ const declared = lowerer.paramShape(param);
1809
+ if ((lowerer.typeOf(param.name).flags & ts.TypeFlags.Any) === 0)
1810
+ bound = declared.type;
1712
1811
  const arg = call.arguments[i];
1713
1812
  if (arg && !ts.isSpreadElement(arg)) {
1813
+ const runtimeLocal = ts.isIdentifier(arg) ? lowerer.peekLocal(arg) : null;
1814
+ if (runtimeLocal?.type.kind === "dyn") {
1815
+ bound = DYN;
1816
+ argTypes.set(sym, lowerer.checker.getUnknownType());
1817
+ shapes.push({ type: bound, mode: "required" });
1818
+ return;
1819
+ }
1714
1820
  // The argument's own checker type, literal-widened ('add' binds
1715
1821
  // string) — typeOf consults the ACTIVE instance's bindings, so a
1716
1822
  // bound param forwarded into another implicit call transitively
1717
1823
  // instantiates it (this._initCommandGroup(command)).
1718
1824
  const t = lowerer.checker.getBaseTypeOfLiteralType(lowerer.typeOf(arg));
1719
- const mapped = lowerer.mapTypeOf(t);
1720
- if (bindableImplicitIr(mapped)) {
1825
+ const mapped = lowerer.mapTypeOf(t) ?? dynFallbackType(lowerer, arg, t);
1826
+ if (ts.isArrowFunction(arg) &&
1827
+ arg.type === undefined &&
1828
+ mapped?.kind === "func" &&
1829
+ promiseCarriesDyn(lowerer, mapped.ret)) {
1830
+ bound = { ...mapped, ret: DYN };
1831
+ lowerer.runtimeOptionalFunctionReturns.set(arg, DYN);
1832
+ argTypes.set(sym, t);
1833
+ }
1834
+ else if (mapped?.kind === "dyn") {
1835
+ bound = DYN;
1836
+ argTypes.set(sym, t);
1837
+ }
1838
+ else if (bindableImplicitIr(mapped)) {
1721
1839
  bound = mapped;
1722
1840
  argTypes.set(sym, t);
1723
1841
  }
@@ -1743,7 +1861,11 @@ function internImplicitInstance(lowerer, blame, info, shapes, argTypes) {
1743
1861
  `${MAX_GENERIC_INSTANCES} instances — polymorphic recursion?)`);
1744
1862
  }
1745
1863
  const rendered = shapes.map((s) => lowerer.fmt(s.type)).join(", ");
1746
- const declared = implicitDeclaredReturn(lowerer, info);
1864
+ const dynamicBroadPromise = info.decl.parameters.some((param, index) => info.implicitParams?.[index] !== null &&
1865
+ info.implicitParams?.[index] !== undefined &&
1866
+ shapes[index]?.type.kind === "dyn" &&
1867
+ broadPromiseParam(lowerer, lowerer.typeOf(param.name)));
1868
+ const declared = dynamicBroadPromise ? null : implicitDeclaredReturn(lowerer, info);
1747
1869
  inst = {
1748
1870
  name: `${info.qualifiedName}%${info.instances.size}`,
1749
1871
  ordinal: info.instances.size,
@@ -2712,6 +2834,11 @@ export function lowerCall(lowerer, expr) {
2712
2834
  if (crServed)
2713
2835
  return crServed;
2714
2836
  }
2837
+ {
2838
+ const resolved = lowerImportMetaResolveCall(lowerer, expr) ?? lowerRequireResolveCall(lowerer, expr);
2839
+ if (resolved)
2840
+ return resolved;
2841
+ }
2715
2842
  // `process.getuid?.()` — intercepted BEFORE the optional-chain
2716
2843
  // machinery (the member always exists on a POSIX target, so the
2717
2844
  // optional call IS the call; `process.getuid` itself has no value
@@ -3141,7 +3268,7 @@ export function lowerCall(lowerer, expr) {
3141
3268
  !expr.expression.questionDotToken &&
3142
3269
  !expr.questionDotToken &&
3143
3270
  !expr.arguments.some((a) => ts.isSpreadElement(a))) {
3144
- const recvProbe = probeLower(lowerer, expr.expression.expression);
3271
+ const recvProbe = tryLowerExpression(lowerer, expr.expression.expression);
3145
3272
  if (recvProbe?.type.kind === "dyn") {
3146
3273
  const args = expr.arguments.map((a) => lowerer.lowerExprExpecting(a, DYN));
3147
3274
  return {
@@ -3287,6 +3414,9 @@ export function lowerCall(lowerer, expr) {
3287
3414
  const cryptoServed = lowerer.lowerCryptoModuleCall(expr, bi, loc);
3288
3415
  if (cryptoServed)
3289
3416
  return cryptoServed;
3417
+ const timersInterval = lowerer.lowerTimersPromisesSetInterval(expr, bi, loc);
3418
+ if (timersInterval)
3419
+ return timersInterval;
3290
3420
  const builtinFn = builtinModuleFnOf(lowerer, bi.module, bi.member);
3291
3421
  if (!builtinFn) {
3292
3422
  // Typed by @types/node (the fallback declarations only declare
@@ -3442,7 +3572,7 @@ export function lowerCall(lowerer, expr) {
3442
3572
  return parsed;
3443
3573
  }
3444
3574
  }
3445
- const probed = probeLower(lowerer, expr.arguments[0]);
3575
+ const probed = tryLowerExpression(lowerer, expr.arguments[0]);
3446
3576
  if (name === "parseFloat" && probed?.type.kind === "string") {
3447
3577
  return { kind: "libCall", fn: "num.parseFloat", args: [probed], type: F64, loc };
3448
3578
  }
@@ -3756,12 +3886,12 @@ export function lowerCall(lowerer, expr) {
3756
3886
  return { kind: "callValue", callee, args, type: callee.type.ret, loc };
3757
3887
  }
3758
3888
  if (ts.isPropertyAccessExpression(expr.expression)) {
3759
- const intrinsic =
3760
- // Builtin namespace imports first (`fs.readFileSync(...)` where fs
3761
- // is `import * as fs from "node:fs"`): the same tables and fences
3762
- // as named builtin imports — before anything below tries to lower
3763
- // the namespace object itself as a receiver.
3764
- lowerer.lowerNamespaceBuiltinCall(expr, expr.expression) ??
3889
+ const intrinsic = fenceNodeModuleMutationCall(lowerer, expr, expr.expression) ??
3890
+ // Builtin namespace imports first (`fs.readFileSync(...)` where fs
3891
+ // is `import * as fs from "node:fs"`): the same tables and fences
3892
+ // as named builtin imports — before anything below tries to lower
3893
+ // the namespace object itself as a receiver.
3894
+ lowerer.lowerNamespaceBuiltinCall(expr, expr.expression) ??
3765
3895
  // The node:perf_hooks spoke: performance.now() and its
3766
3896
  // .bind(performance) function value over the runtime's
3767
3897
  // process-start-anchored monotonic clock.
@@ -4379,7 +4509,7 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
4379
4509
  // evolving `let h = {}` object flowing back out of a JS helper —
4380
4510
  // tsc types the return by the evolved shape, the binding lowered
4381
4511
  // dyn): probe the lowering and claim exactly the dyn results.
4382
- const probed = probeLower(lowerer, access.expression);
4512
+ const probed = tryLowerExpression(lowerer, access.expression);
4383
4513
  if (probed?.type.kind !== "dyn")
4384
4514
  return null;
4385
4515
  recv = probed;
@@ -4572,6 +4702,71 @@ export function lowerDynDispatchMethodCall(lowerer, call, access, recv, arrayRec
4572
4702
  if (arrayReceiver && predicate?.type.kind === "func" && predicate.type.ret.kind === "void") {
4573
4703
  lowerer.unsupported("SC1090", call.arguments[0], "'.filter()' with a void-returning predicate (the callback return value is erased before its truthiness can be tested)");
4574
4704
  }
4705
+ // A dynamic argument array consumed immediately by the fixed-arity arrow
4706
+ // apply lowering below never exposes its surplus tail. Keep a pushed
4707
+ // static-only value's evaluation and the array length mutation, but store
4708
+ // undefined in that unobserved slot so no impossible dyn conversion is
4709
+ // invented. If the slot falls inside the typed prefix, its dynCheck fails
4710
+ // at the callback boundary; valid callers preserve the original prefix.
4711
+ if (method === "push" &&
4712
+ call.arguments.length === 1 &&
4713
+ ts.isIdentifier(access.expression) &&
4714
+ ts.isExpressionStatement(call.parent) &&
4715
+ ts.isBlock(call.parent.parent)) {
4716
+ const receiverSymbol = lowerer.checker.getSymbolAtLocation(access.expression);
4717
+ const block = call.parent.parent;
4718
+ const statementIndex = block.statements.indexOf(call.parent);
4719
+ const next = statementIndex >= 0 ? block.statements[statementIndex + 1] : undefined;
4720
+ let returned = next && ts.isReturnStatement(next) ? next.expression : undefined;
4721
+ while (returned && ts.isParenthesizedExpression(returned))
4722
+ returned = returned.expression;
4723
+ const apply = returned && ts.isCallExpression(returned) &&
4724
+ ts.isPropertyAccessExpression(returned.expression) &&
4725
+ returned.expression.name.text === "apply"
4726
+ ? returned
4727
+ : null;
4728
+ const argsNode = apply?.arguments[1];
4729
+ const sameArgs = receiverSymbol !== undefined &&
4730
+ argsNode !== undefined &&
4731
+ ts.isIdentifier(argsNode) &&
4732
+ lowerer.checker.getSymbolAtLocation(argsNode) === receiverSymbol;
4733
+ const applyAccess = apply && ts.isPropertyAccessExpression(apply.expression)
4734
+ ? apply.expression
4735
+ : null;
4736
+ const applyTarget = applyAccess?.expression;
4737
+ const arrow = applyTarget ? arrowSignatureOf(lowerer, applyTarget) : null;
4738
+ const target = applyTarget && ts.isIdentifier(applyTarget)
4739
+ ? lowerer.peekLocal(applyTarget)
4740
+ : null;
4741
+ const targetParams = target?.type.kind === "func" && target.type.rest !== true
4742
+ ? target.type.params
4743
+ : null;
4744
+ if (sameArgs && arrow !== null && targetParams !== null &&
4745
+ targetParams.every((param) => canDynCheckTo(param, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id)))) {
4746
+ const value = lowerer.lowerExpr(call.arguments[0]);
4747
+ if (value.type.kind !== "dyn" && !lowerer.dynConvertible(value.type)) {
4748
+ const saved = lowerer.declareHiddenLocal("%applyTail", DYN);
4749
+ return {
4750
+ kind: "seqExpr",
4751
+ stmts: [
4752
+ { kind: "varDecl", localId: saved.id, init: recv, loc: locOf(access.expression) },
4753
+ { kind: "exprStmt", expr: value, loc: value.loc },
4754
+ ],
4755
+ result: {
4756
+ kind: "dynInvoke",
4757
+ recv: { kind: "varRef", localId: saved.id, type: DYN, loc: locOf(access.expression) },
4758
+ method,
4759
+ calleeName: access.getText(),
4760
+ args: [dynUndefinedExpr(locOf(call.arguments[0]))],
4761
+ type: DYN,
4762
+ loc: locOf(call),
4763
+ },
4764
+ type: DYN,
4765
+ loc: locOf(call),
4766
+ };
4767
+ }
4768
+ }
4769
+ }
4575
4770
  const args = call.arguments.map((arg, i) => i === 0 && predicate ? lowerer.coerceInto(arg, predicate, DYN) : lowerer.lowerExprExpecting(arg, DYN));
4576
4771
  return {
4577
4772
  kind: "dynInvoke",
@@ -4924,7 +5119,7 @@ function lowerPrimitiveProtoCall(lowerer, call, recv, name, memberSym) {
4924
5119
  // optional number selects 0 at runtime through the same narrowed
4925
5120
  // nullish IR used by `digits ?? 0`.
4926
5121
  const zero = { kind: "numLit", value: 0, type: F64, loc: digits.loc };
4927
- const defaultUnitDigits = (value) => droppableStatic(value)
5122
+ const defaultUnitDigits = (value) => isSafeToDiscard(value)
4928
5123
  ? zero
4929
5124
  : {
4930
5125
  kind: "seqExpr",
@@ -5010,6 +5205,46 @@ function lowerPrimitiveProtoCall(lowerer, call, recv, name, memberSym) {
5010
5205
  return null;
5011
5206
  return { kind: "boolLit", value: false, type: BOOL, loc };
5012
5207
  }
5208
+ /** The uniquely arity-selected overload on an implicit-any receiver whose
5209
+ * active monomorphization supplies a concrete type. The checker resolved
5210
+ * the original call through `any`, so getResolvedSignature cannot name
5211
+ * the declaration-authored overload; typeOf carries the instance's real
5212
+ * receiver type. Restricting the fallback to exactly one bodyless
5213
+ * signature at this arity avoids recreating TypeScript's overload
5214
+ * resolution for same-arity type distinctions. */
5215
+ function implicitReceiverOverloadReturn(lowerer, expr) {
5216
+ if (!ts.isCallExpression(expr) ||
5217
+ !ts.isPropertyAccessExpression(expr.expression) ||
5218
+ expr.arguments.some(ts.isSpreadElement)) {
5219
+ return null;
5220
+ }
5221
+ const access = expr.expression;
5222
+ const original = lowerer.checker.getTypeAtLocation(access.expression);
5223
+ if ((original.flags & ts.TypeFlags.Any) === 0)
5224
+ return null;
5225
+ const effective = lowerer.typeOf(access.expression);
5226
+ if ((effective.flags & ts.TypeFlags.Any) !== 0)
5227
+ return null;
5228
+ const member = lowerer.checker.getPropertyOfType(effective, access.name.text);
5229
+ if (!member)
5230
+ return null;
5231
+ const signatures = lowerer.checker.getCallSignatures(lowerer.checker.getTypeOfSymbol(member));
5232
+ const matches = signatures.filter((signature) => {
5233
+ const decl = lowerer.checker.signatureDeclaration(signature);
5234
+ if (!decl ||
5235
+ !(ts.isFunctionDeclaration(decl) || ts.isMethodDeclaration(decl)) ||
5236
+ decl.body) {
5237
+ return false;
5238
+ }
5239
+ const params = decl.parameters.filter((param) => !isThisParameter(param));
5240
+ const required = params.filter((param) => !param.questionToken && !param.initializer && !param.dotDotDotToken).length;
5241
+ const maximum = params.some((param) => param.dotDotDotToken) ? Infinity : params.length;
5242
+ return expr.arguments.length >= required && expr.arguments.length <= maximum;
5243
+ });
5244
+ if (matches.length !== 1)
5245
+ return null;
5246
+ return lowerer.mapTypeOf(lowerer.checker.getReturnTypeOfSignature(matches[0]));
5247
+ }
5013
5248
  /** Reconciles a direct call's recorded type with the checker's answer at
5014
5249
  * the site when the callee is OVERLOADED: tsc resolved the call against
5015
5250
  * one overload SIGNATURE, so every downstream lowering sees that
@@ -5029,10 +5264,12 @@ function lowerPrimitiveProtoCall(lowerer, call, recv, name, memberSym) {
5029
5264
  function reconcileOverloadReturn(lowerer, expr, call) {
5030
5265
  const rsig = lowerer.checker.getResolvedSignature(expr);
5031
5266
  const rdecl = rsig ? lowerer.checker.signatureDeclaration(rsig) : undefined;
5032
- if (!rsig || !rdecl || !(ts.isFunctionDeclaration(rdecl) || ts.isMethodDeclaration(rdecl)) || rdecl.body) {
5033
- return call;
5034
- }
5035
- const rt = lowerer.mapTypeOf(lowerer.checker.getReturnTypeOfSignature(rsig));
5267
+ const resolvedOverload = rsig && rdecl &&
5268
+ (ts.isFunctionDeclaration(rdecl) || ts.isMethodDeclaration(rdecl)) &&
5269
+ !rdecl.body
5270
+ ? lowerer.mapTypeOf(lowerer.checker.getReturnTypeOfSignature(rsig))
5271
+ : null;
5272
+ const rt = resolvedOverload ?? implicitReceiverOverloadReturn(lowerer, expr);
5036
5273
  // Unmappable, void, or unit resolved returns keep the implementation's
5037
5274
  // type: a discarded result never looks, a USED one meets its use
5038
5275
  // site's own mapping (and that site's honest fences). Unit narrowing
@@ -5312,10 +5549,6 @@ export function lowerNestedFunctionDecl(lowerer, stmt) {
5312
5549
  export function lambdaSignature(lowerer, node) {
5313
5550
  if (!node.body)
5314
5551
  lowerer.unsupported("SC1090", node, "function overload signatures");
5315
- if (node.asteriskToken &&
5316
- node.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword)) {
5317
- lowerer.unsupported("SC1071", node, "async generators (async function*)");
5318
- }
5319
5552
  if (node.typeParameters) {
5320
5553
  // Generic function-like forms monomorphize only where a static home
5321
5554
  // exists: top-level generic function declarations, generic methods
@@ -5486,13 +5719,14 @@ export function lowerLambda(lowerer, node) {
5486
5719
  // the lifted body returns the inner T (a `return v` fulfills with v).
5487
5720
  const isAsync = !ts.isAccessor(node) &&
5488
5721
  node.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) === true;
5489
- if (isAsync && funcType.ret.kind !== "promise")
5722
+ const isGenerator = node.asteriskToken !== undefined;
5723
+ if (isAsync && !isGenerator && funcType.ret.kind !== "promise")
5490
5724
  lowerer.badType(node, lowerer.typeOf(node));
5491
5725
  // Generator lambdas (function* expressions and object-literal
5492
5726
  // *methods): the VALUE's type returns the generator; the lifted body
5493
5727
  // returns the TReturn channel (a `return v` is the done-value).
5494
- const isGenerator = node.asteriskToken !== undefined;
5495
- if (isGenerator && funcType.ret.kind !== "generator")
5728
+ if (isGenerator &&
5729
+ (funcType.ret.kind !== "generator" || (funcType.ret.async === true) !== isAsync))
5496
5730
  lowerer.badType(node, lowerer.typeOf(node));
5497
5731
  const bodyReturn = isGenerator
5498
5732
  ? lowerer.genBodyReturnType(funcType.ret)
@@ -5500,7 +5734,7 @@ export function lowerLambda(lowerer, node) {
5500
5734
  const fnCtx = newFnCtx(true, selfSymbol, funcType, bodyReturn);
5501
5735
  fnCtx.isAsync = isAsync;
5502
5736
  if (isGenerator && funcType.ret.kind === "generator") {
5503
- fnCtx.generator = { yieldT: funcType.ret.yieldT, nextT: funcType.ret.nextT };
5737
+ fnCtx.generator = generatorMeta(lowerer, funcType.ret);
5504
5738
  }
5505
5739
  const diagsBefore = lowerer.diags.length;
5506
5740
  lowerer.fnStack.push(fnCtx);
@@ -6842,7 +7076,7 @@ function lowerIntlNumberFormatCall(lowerer, call, access) {
6842
7076
  function objectIsDisjointFalse(left, right, loc) {
6843
7077
  const stmts = [];
6844
7078
  for (const e of [left, right]) {
6845
- if (!droppableStatic(e))
7079
+ if (!isSafeToDiscard(e))
6846
7080
  stmts.push({ kind: "exprStmt", expr: e, loc });
6847
7081
  }
6848
7082
  const answer = { kind: "boolLit", value: false, type: BOOL, loc };
@@ -6856,6 +7090,9 @@ function lowerObjectStaticCall(lowerer, call, access) {
6856
7090
  if (!lowerer.isStdlibGlobal(access.expression, "Object"))
6857
7091
  return null;
6858
7092
  const member = access.name.text;
7093
+ const cacheKeys = lowerRequireCacheKeys(lowerer, call, member);
7094
+ if (cacheKeys)
7095
+ return cacheKeys;
6859
7096
  // Object.is — the spec's SameValue over the static kinds. Number
6860
7097
  // pairs take the runtime SameValue (NaN equals NaN, +0 differs from
6861
7098
  // -0 — the two divergences from ===); every other supported pair
@@ -7046,8 +7283,8 @@ function lowerObjectStaticCall(lowerer, call, access) {
7046
7283
  // the explicit-undefined-is-absent stance). Everything else keeps
7047
7284
  // the spread hint.
7048
7285
  if (call.arguments.length === 2 && !call.arguments.some((a) => ts.isSpreadElement(a))) {
7049
- const tProbe = probeLower(lowerer, call.arguments[0]);
7050
- const sProbe = probeLower(lowerer, call.arguments[1]);
7286
+ const tProbe = tryLowerExpression(lowerer, call.arguments[0]);
7287
+ const sProbe = tryLowerExpression(lowerer, call.arguments[1]);
7051
7288
  // CHECKED-DYNAMIC target and source (the JS file-scope
7052
7289
  // object-literal identity story): the runtime dyn copy — own
7053
7290
  // members of the source land on the target, which returns.
@@ -7105,7 +7342,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
7105
7342
  while (ts.isParenthesizedExpression(targetNode))
7106
7343
  targetNode = targetNode.expression;
7107
7344
  const freshLiteralTarget = ts.isObjectLiteralExpression(targetNode);
7108
- const tProbe = freshLiteralTarget ? null : probeLower(lowerer, call.arguments[0]);
7345
+ const tProbe = freshLiteralTarget ? null : tryLowerExpression(lowerer, call.arguments[0]);
7109
7346
  const tKind = tProbe?.type.kind;
7110
7347
  if (freshLiteralTarget || tKind === "dyn" || tKind === "nullT" || tKind === "undefinedT") {
7111
7348
  const loc = locOf(call);
@@ -7177,7 +7414,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
7177
7414
  // static shapes have no property table to extend.
7178
7415
  if (member === "defineProperties" && call.arguments.length === 2 &&
7179
7416
  !call.arguments.some((a) => ts.isSpreadElement(a))) {
7180
- let target = probeLower(lowerer, call.arguments[0]);
7417
+ let target = tryLowerExpression(lowerer, call.arguments[0]);
7181
7418
  // A FUNCTION-typed target boxes through the dyn boundary: the
7182
7419
  // property table lives on the CLOSURE (shared by every box of this
7183
7420
  // function value), so defining through a fresh box sticks — the
@@ -7232,7 +7469,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
7232
7469
  if (member === "hasOwn" && call.arguments.length === 2 && !call.arguments.some((a) => ts.isSpreadElement(a))) {
7233
7470
  const recvNode = call.arguments[0];
7234
7471
  const keyNode = call.arguments[1];
7235
- const probed = probeLower(lowerer, recvNode);
7472
+ const probed = tryLowerExpression(lowerer, recvNode);
7236
7473
  // A CHECKED-DYNAMIC receiver (the JS file-scope object-literal
7237
7474
  // identity story): the runtime dyn probe — OBJ member presence, ARR
7238
7475
  // index bounds, Node's ToObject TypeError on nullish.
@@ -7278,7 +7515,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
7278
7515
  // runtime walks the dyn node's own keys (integer-like keys first,
7279
7516
  // JS's own-key order) and answers a dyn array.
7280
7517
  {
7281
- const probed = probeLower(lowerer, argNode);
7518
+ const probed = tryLowerExpression(lowerer, argNode);
7282
7519
  const isDyn = probed?.type.kind === "dyn";
7283
7520
  // Unit-typed arguments (Object.keys(null)) ride the same runtime
7284
7521
  // walk: it throws Node's catchable TypeError.
@@ -7296,7 +7533,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
7296
7533
  // record (the narrowed export-table literal) — the lowered value's
7297
7534
  // shape is the honest dispatch key, exactly the identity-Set stance.
7298
7535
  if (argIr === null && isJsSourceFile(argNode.getSourceFile())) {
7299
- const probed = probeLower(lowerer, argNode);
7536
+ const probed = tryLowerExpression(lowerer, argNode);
7300
7537
  if (probed?.type.kind === "record")
7301
7538
  argIr = probed.type;
7302
7539
  }
@@ -8337,6 +8574,69 @@ const SP_BRAND_METHODS = new Set([
8337
8574
  "append", "delete", "get", "getAll", "has", "set", "sort",
8338
8575
  "forEach", "keys", "values", "entries", "toString",
8339
8576
  ]);
8577
+ function arrowSignatureOf(lowerer, node) {
8578
+ const signatures = lowerer.checker.getCallSignatures(lowerer.typeOf(node));
8579
+ if (signatures.length !== 1)
8580
+ return null;
8581
+ const declaration = lowerer.checker.signatureDeclaration(signatures[0]);
8582
+ return declaration !== undefined && ts.isArrowFunction(declaration) ? signatures[0] : null;
8583
+ }
8584
+ /** `arrow.apply(thisArg, dynArgs)` for a fixed-arity compiled arrow. Arrows
8585
+ * ignore `thisArg` and surplus arguments by language definition; declared
8586
+ * parameters validate from the dynamic array in order. */
8587
+ function lowerArrowFunctionApply(lowerer, call, access) {
8588
+ if (access.name.text !== "apply" ||
8589
+ call.arguments.length !== 2 ||
8590
+ call.arguments.some(ts.isSpreadElement) ||
8591
+ arrowSignatureOf(lowerer, access.expression) === null) {
8592
+ return null;
8593
+ }
8594
+ const callee = lowerer.lowerExpr(access.expression);
8595
+ if (callee.type.kind !== "func" || callee.type.rest === true)
8596
+ return null;
8597
+ if (!callee.type.params.every((param) => canDynCheckTo(param, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id)))) {
8598
+ return null;
8599
+ }
8600
+ const argsList = lowerer.lowerExpr(call.arguments[1]);
8601
+ if (argsList.type.kind !== "dyn")
8602
+ return null;
8603
+ const loc = locOf(call);
8604
+ const savedCallee = lowerer.declareHiddenLocal("%applyFn", callee.type);
8605
+ const savedArgs = lowerer.declareHiddenLocal("%applyArgs", DYN);
8606
+ const stmts = [
8607
+ { kind: "varDecl", localId: savedCallee.id, init: callee, loc },
8608
+ { kind: "exprStmt", expr: lowerer.lowerExpr(call.arguments[0]), loc },
8609
+ { kind: "varDecl", localId: savedArgs.id, init: argsList, loc },
8610
+ ];
8611
+ const args = callee.type.params.map((param, index) => {
8612
+ const read = {
8613
+ kind: "dynKeyGet",
8614
+ key: { kind: "strLit", value: String(index), type: STRING, loc },
8615
+ value: { kind: "varRef", localId: savedArgs.id, type: DYN, loc },
8616
+ type: DYN,
8617
+ loc,
8618
+ };
8619
+ return lowerer.coerceInto(call.arguments[1], read, param);
8620
+ });
8621
+ const invoked = {
8622
+ kind: "callValue",
8623
+ callee: { kind: "varRef", localId: savedCallee.id, type: callee.type, loc },
8624
+ args,
8625
+ type: callee.type.ret,
8626
+ loc,
8627
+ };
8628
+ let result;
8629
+ if (invoked.type.kind === "void") {
8630
+ stmts.push({ kind: "exprStmt", expr: invoked, loc });
8631
+ result = dynUndefinedExpr(loc);
8632
+ }
8633
+ else {
8634
+ result = lowerer.coerceInto(call, invoked, DYN);
8635
+ if (result.type.kind !== "dyn")
8636
+ return null;
8637
+ }
8638
+ return { kind: "seqExpr", stmts, result, type: DYN, loc };
8639
+ }
8340
8640
  function lowerObjLitGenericMethodCall(lowerer, call, access) {
8341
8641
  if (lowerer.chainBlocked(access, call))
8342
8642
  return null;
@@ -8398,6 +8698,9 @@ function lowerObjLitGenericMethodCall(lowerer, call, access) {
8398
8698
  }
8399
8699
  const found = objLitGenericFnNodeOf(lowerer, propSym);
8400
8700
  if (!found) {
8701
+ const arrowApply = lowerArrowFunctionApply(lowerer, call, access);
8702
+ if (arrowApply !== null)
8703
+ return arrowApply;
8401
8704
  // Function.prototype.apply/call/bind spelled through a FUNCTION
8402
8705
  // receiver: compiled functions are direct calls with no runtime
8403
8706
  // `this`/arguments object to re-route — name the working spelling
@@ -8444,9 +8747,32 @@ function lowerObjLitGenericMethodCall(lowerer, call, access) {
8444
8747
  export function lowerObjectMethodCall(lowerer, call, access) {
8445
8748
  if (lowerer.chainBlocked(access, call))
8446
8749
  return null;
8447
- const receiverIr = lowerer.mapTypeOf(lowerer.typeOf(access.expression));
8448
- if (receiverIr?.kind !== "object")
8750
+ const mappedReceiver = lowerer.mapTypeOf(lowerer.typeOf(access.expression));
8751
+ const receiverIr = mappedReceiver?.kind === "object"
8752
+ ? mappedReceiver
8753
+ : mappedReceiver?.kind === "union"
8754
+ ? (() => {
8755
+ const arms = lowerer.unions.get(mappedReceiver.unionId)?.arms ?? [];
8756
+ const objects = arms.filter((arm) => arm.kind === "object");
8757
+ return objects.length === 1 && arms.every((arm) => arm.kind === "object" || isUnitType(arm))
8758
+ ? objects[0]
8759
+ : null;
8760
+ })()
8761
+ : null;
8762
+ if (receiverIr === null)
8449
8763
  return null;
8764
+ const lowerReceiver = () => {
8765
+ const receiver = lowerer.lowerExpr(access.expression);
8766
+ const optional = lowerer.runtimeOptionalPropertyReceiver(access.expression, receiver, receiverIr, access.name.text);
8767
+ if (optional !== null)
8768
+ return optional;
8769
+ if (receiver.type.kind === "union") {
8770
+ const helper = lowerer.narrowedArmHelper(receiver.type.unionId, receiverIr, locOf(access.expression));
8771
+ if (helper !== null)
8772
+ return { kind: "call", callee: helper, args: [receiver], type: receiverIr, loc: locOf(access.expression) };
8773
+ }
8774
+ return receiver;
8775
+ };
8450
8776
  const info = lowerer.classes.get(receiverIr.className);
8451
8777
  if (!info)
8452
8778
  lowerer.flushDeferredClass(receiverIr.className);
@@ -8474,17 +8800,34 @@ export function lowerObjectMethodCall(lowerer, call, access) {
8474
8800
  if (gfound)
8475
8801
  return lowerClassGenericMethodCall(lowerer, call, access, info, gfound);
8476
8802
  }
8477
- // A FUNC- or DYN-typed FIELD in call position: `this.cb()` — the
8478
- // ctor-assigned callback field (countdown.js's shape). The call is an
8479
- // ordinary call through the field's VALUE — read the field, then
8480
- // callValue (func fields) or the dynCall boundary (checked-dynamic
8481
- // fields: implicit-any ctor params, validated at the call like every
8482
- // dyn callee). Every other field type falls through to the fences.
8803
+ // A FUNC-, nullable-FUNC-, or DYN-typed FIELD in call position:
8804
+ // `this.cb()` — the ctor-assigned callback field (countdown.js's
8805
+ // shape). The call is an ordinary call through the field's VALUE —
8806
+ // read and, when necessary, check-narrow the callable arm, then
8807
+ // callValue; checked-dynamic fields use the dynCall boundary. Every
8808
+ // other field type falls through to the fences.
8483
8809
  if (info && !found) {
8484
8810
  const fieldType = info.fields.get(access.name.text);
8485
- if (fieldType && (fieldType.kind === "func" || fieldType.kind === "dyn")) {
8811
+ const callableType = fieldType?.kind === "func"
8812
+ ? fieldType
8813
+ : fieldType?.kind === "union"
8814
+ ? (() => {
8815
+ const arms = lowerer.unions.get(fieldType.unionId)?.arms ?? [];
8816
+ const funcs = arms.filter((arm) => arm.kind === "func");
8817
+ return funcs.length === 1 && arms.every((arm) => arm.kind === "func" || isUnitType(arm))
8818
+ ? funcs[0]
8819
+ : null;
8820
+ })()
8821
+ : null;
8822
+ if (fieldType && (callableType !== null || fieldType.kind === "dyn")) {
8486
8823
  const target = lowerer.fieldTarget(access);
8487
- const callee = target ? lowerer.fieldGetExpr(target, locOf(access), access) : null;
8824
+ let callee = target ? lowerer.fieldGetExpr(target, locOf(access), access) : null;
8825
+ if (callee?.type.kind === "union" && callableType !== null) {
8826
+ const helper = lowerer.narrowedArmHelper(callee.type.unionId, callableType, locOf(access));
8827
+ if (helper !== null) {
8828
+ callee = { kind: "call", callee: helper, args: [callee], type: callableType, loc: locOf(access) };
8829
+ }
8830
+ }
8488
8831
  if (callee?.type.kind === "func") {
8489
8832
  const params = callee.type.params;
8490
8833
  const args = call.arguments.map((a, i) => lowerer.lowerExprExpecting(a, params[i]));
@@ -8514,7 +8857,7 @@ export function lowerObjectMethodCall(lowerer, call, access) {
8514
8857
  // The one builtin method: Error.prototype.toString, a runtime
8515
8858
  // implementation called directly (overriding it is fenced, so no
8516
8859
  // dispatch can ever be needed). Receiver BORROWED by the libCall.
8517
- const receiver = lowerer.lowerExpr(access.expression);
8860
+ const receiver = lowerReceiver();
8518
8861
  return {
8519
8862
  kind: "libCall",
8520
8863
  fn: "error.toString",
@@ -8536,7 +8879,7 @@ export function lowerObjectMethodCall(lowerer, call, access) {
8536
8879
  lowerer.noteVirtualEdge(info, method);
8537
8880
  else
8538
8881
  lowerer.noteEdge(`%${found.declarer.def.name}.${method}`);
8539
- const receiver = lowerer.lowerExpr(access.expression);
8882
+ const receiver = lowerReceiver();
8540
8883
  const args = lowerer.completeArgs(call.arguments, found.sig.params, locOf(call), call);
8541
8884
  if (lowerer.overrideBelow(info, method)) {
8542
8885
  return reconcileOverloadReturn(lowerer, call, {