@scriptc/compiler 0.1.5 → 0.1.7

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 (139) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +0 -1
  2. package/ambient/scriptc.d.ts +13 -5
  3. package/dist/backend/c/c-emitter.d.ts +5 -0
  4. package/dist/backend/c/c-emitter.js +15 -0
  5. package/dist/backend/c/c-emitter.js.map +1 -1
  6. package/dist/backend/c/exprs.js +81 -9
  7. package/dist/backend/c/exprs.js.map +1 -1
  8. package/dist/backend/c/stmts.js +25 -1
  9. package/dist/backend/c/stmts.js.map +1 -1
  10. package/dist/backend/c/walkers.js +2 -3
  11. package/dist/backend/c/walkers.js.map +1 -1
  12. package/dist/backend/debug-symbols.d.ts +8 -0
  13. package/dist/backend/debug-symbols.js +52 -0
  14. package/dist/backend/debug-symbols.js.map +1 -0
  15. package/dist/backend/link-plan.d.ts +1 -0
  16. package/dist/backend/link-plan.js +2 -0
  17. package/dist/backend/link-plan.js.map +1 -1
  18. package/dist/backend/linker.js +8 -0
  19. package/dist/backend/linker.js.map +1 -1
  20. package/dist/backend/llvm/blocks.d.ts +2 -0
  21. package/dist/backend/llvm/blocks.js +18 -2
  22. package/dist/backend/llvm/blocks.js.map +1 -1
  23. package/dist/backend/llvm/debug-info.d.ts +32 -0
  24. package/dist/backend/llvm/debug-info.js +203 -0
  25. package/dist/backend/llvm/debug-info.js.map +1 -0
  26. package/dist/backend/llvm/dyn.js +4 -10
  27. package/dist/backend/llvm/dyn.js.map +1 -1
  28. package/dist/backend/llvm/emitter.d.ts +2 -0
  29. package/dist/backend/llvm/emitter.js +49 -4
  30. package/dist/backend/llvm/emitter.js.map +1 -1
  31. package/dist/backend/llvm/expr-containers.js +28 -2
  32. package/dist/backend/llvm/expr-containers.js.map +1 -1
  33. package/dist/backend/llvm/expr-dynamic.js +10 -0
  34. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  35. package/dist/backend/llvm/lib-filesystem.js +37 -0
  36. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  37. package/dist/backend/llvm/lib-process.js +4 -3
  38. package/dist/backend/llvm/lib-process.js.map +1 -1
  39. package/dist/backend/llvm/lib-shared.js +9 -0
  40. package/dist/backend/llvm/lib-shared.js.map +1 -1
  41. package/dist/backend/llvm/split.js +4 -1
  42. package/dist/backend/llvm/split.js.map +1 -1
  43. package/dist/backend/llvm/split.test.js +26 -1
  44. package/dist/backend/llvm/split.test.js.map +1 -1
  45. package/dist/backend/native-toolchain.js +58 -8
  46. package/dist/backend/native-toolchain.js.map +1 -1
  47. package/dist/backend/native-toolchain.test.js +10 -0
  48. package/dist/backend/native-toolchain.test.js.map +1 -1
  49. package/dist/backend/source-locations.d.ts +12 -0
  50. package/dist/backend/source-locations.js +32 -0
  51. package/dist/backend/source-locations.js.map +1 -0
  52. package/dist/backend/source-locations.test.d.ts +1 -0
  53. package/dist/backend/source-locations.test.js +16 -0
  54. package/dist/backend/source-locations.test.js.map +1 -0
  55. package/dist/coverage/surface-manifest.js +6 -1
  56. package/dist/coverage/surface-manifest.js.map +1 -1
  57. package/dist/diagnostics/diagnostic.d.ts +4 -0
  58. package/dist/diagnostics/diagnostic.js +12 -0
  59. package/dist/diagnostics/diagnostic.js.map +1 -1
  60. package/dist/executable/executable-cache.js +28 -4
  61. package/dist/executable/executable-cache.js.map +1 -1
  62. package/dist/executable/executable-cache.test.js +23 -0
  63. package/dist/executable/executable-cache.test.js.map +1 -1
  64. package/dist/frontend/arguments-usage.d.ts +6 -0
  65. package/dist/frontend/arguments-usage.js +40 -0
  66. package/dist/frontend/arguments-usage.js.map +1 -0
  67. package/dist/frontend/binding-source.d.ts +4 -0
  68. package/dist/frontend/binding-source.js +18 -0
  69. package/dist/frontend/binding-source.js.map +1 -0
  70. package/dist/frontend/lowering/array-indexed-mutation.d.ts +8 -0
  71. package/dist/frontend/lowering/array-indexed-mutation.js +176 -0
  72. package/dist/frontend/lowering/array-indexed-mutation.js.map +1 -0
  73. package/dist/frontend/lowering/containers/string-and-regexp.d.ts +7 -0
  74. package/dist/frontend/lowering/containers/string-and-regexp.js +190 -13
  75. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  76. package/dist/frontend/lowering/expressions/object-literals.js +13 -8
  77. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  78. package/dist/frontend/lowering/expressions/optional-chains.d.ts +5 -6
  79. package/dist/frontend/lowering/expressions/optional-chains.js +7 -6
  80. package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
  81. package/dist/frontend/lowering/indexed-comparison.d.ts +6 -0
  82. package/dist/frontend/lowering/indexed-comparison.js +30 -0
  83. package/dist/frontend/lowering/indexed-comparison.js.map +1 -0
  84. package/dist/frontend/lowering/lower-builtins.d.ts +1 -1
  85. package/dist/frontend/lowering/lower-builtins.js +21 -10
  86. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  87. package/dist/frontend/lowering/lower-calls.d.ts +2 -9
  88. package/dist/frontend/lowering/lower-calls.js +406 -40
  89. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  90. package/dist/frontend/lowering/lower-classes.js +3 -27
  91. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  92. package/dist/frontend/lowering/lower-containers.d.ts +8 -2
  93. package/dist/frontend/lowering/lower-containers.js +454 -104
  94. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  95. package/dist/frontend/lowering/lower-exprs.js +134 -18
  96. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  97. package/dist/frontend/lowering/lower-island.d.ts +1 -1
  98. package/dist/frontend/lowering/lower-island.js +1 -1
  99. package/dist/frontend/lowering/lower-modules.js +19 -8
  100. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  101. package/dist/frontend/lowering/lower-stmts.js +4 -37
  102. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  103. package/dist/frontend/lowering/lowerer.js +14 -3
  104. package/dist/frontend/lowering/lowerer.js.map +1 -1
  105. package/dist/frontend/lowering/surfaces.d.ts +3 -1
  106. package/dist/frontend/lowering/surfaces.js +50 -7
  107. package/dist/frontend/lowering/surfaces.js.map +1 -1
  108. package/dist/frontend/program.d.ts +5 -0
  109. package/dist/frontend/program.js +216 -32
  110. package/dist/frontend/program.js.map +1 -1
  111. package/dist/frontend/program.test.d.ts +1 -0
  112. package/dist/frontend/program.test.js +117 -0
  113. package/dist/frontend/program.test.js.map +1 -0
  114. package/dist/frontend/type-mapper.d.ts +4 -2
  115. package/dist/frontend/type-mapper.js +249 -186
  116. package/dist/frontend/type-mapper.js.map +1 -1
  117. package/dist/frontend/type-mapper.test.d.ts +1 -0
  118. package/dist/frontend/type-mapper.test.js +86 -0
  119. package/dist/frontend/type-mapper.test.js.map +1 -0
  120. package/dist/index.d.ts +2 -1
  121. package/dist/index.js +7 -2
  122. package/dist/index.js.map +1 -1
  123. package/dist/ir/analysis.js +4 -2
  124. package/dist/ir/analysis.js.map +1 -1
  125. package/dist/ir/ir.d.ts +33 -14
  126. package/dist/ir/ir.js +5 -1
  127. package/dist/ir/ir.js.map +1 -1
  128. package/dist/ir/validate.js +57 -31
  129. package/dist/ir/validate.js.map +1 -1
  130. package/dist/ir/validate.test.js +17 -0
  131. package/dist/ir/validate.test.js.map +1 -1
  132. package/dist/library/compiler-self-identity.d.ts +1 -1
  133. package/dist/library/compiler-self-identity.js +31 -15
  134. package/dist/library/compiler-self-identity.js.map +1 -1
  135. package/dist/library/compiler-self-identity.test.d.ts +1 -0
  136. package/dist/library/compiler-self-identity.test.js +93 -0
  137. package/dist/library/compiler-self-identity.test.js.map +1 -0
  138. package/package.json +17 -17
  139. package/surface-manifest.json +155 -4
@@ -1,8 +1,10 @@
1
1
  import * as ts from "../ts7/adapter.js";
2
+ import { bodyReadsArguments } from "../arguments-usage.js";
2
3
  import type { Lowerer } from "./lowerer.js";
3
4
  import { IrExpr, IrFunction, IrStmt, IrType, SrcLoc } from "../../ir/ir.js";
4
5
  import type { ScrDiagnostic } from "../../diagnostics/diagnostic.js";
5
6
  import { type ClassInfo } from "./lower-classes.js";
7
+ export { bodyReadsArguments };
6
8
  /** How a parameter participates in CALL-SITE COMPLETION (the frontend
7
9
  * completes every call to the one full signature, so the IR and backends
8
10
  * stay count-exact — see docs/ir.md). `required` params must be passed;
@@ -423,15 +425,6 @@ export declare function lambdaSignature(lowerer: Lowerer, node: ts.ArrowFunction
423
425
  kind: "func";
424
426
  };
425
427
  };
426
- /** Does this function's OWN body read `arguments`? Nested plain functions
427
- * and methods have their own `arguments` (the walk skips them); arrows
428
- * see the enclosing one (the walk descends). Exported for the lowerer's
429
- * dynFallbackType: tsgo does not synthesize the `arguments` rest
430
- * parameter into inferred signatures (5.9.3 did — its param-count
431
- * mismatch was the detector), so the 7 world asks the BODY directly. */
432
- export declare function bodyReadsArguments(fn: {
433
- body?: ts.Node | undefined;
434
- }): boolean;
435
428
  /** Lifts an arrow function / function expression / nested declaration /
436
429
  * object-literal shorthand method to a module-level function and yields
437
430
  * the `closure` expression creating it. */
@@ -4,18 +4,19 @@ import { InternalCompilerError } from "../../errors.js";
4
4
  * function/lambda lowering and signature collection, and monomorphizing
5
5
  * generic instantiation (bounded by MAX_GENERIC_INSTANCES). */
6
6
  import * as ts from "../ts7/adapter.js";
7
+ import { bodyReadsArguments } from "../arguments-usage.js";
7
8
  import { lowerGenMethodCall } from "./lower-generators.js";
8
9
  import { BIGINT_T, 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";
9
10
  import { isJsSourceFile, isNodeEsmFile, locOf } from "../program.js";
10
11
  import { genResultRecord, isGenericCallableMemberType, typeKey } from "../type-mapper.js";
11
12
  import { PoisonError, dynFallbackType, dynUndefinedExpr, importCallHandleType, jsFuncNameOf, newFnCtx, nodeThrowExpr, staticImportNamespaceType } from "./lowerer.js";
12
13
  import { enforceLibBoundary } from "./lib-boundary.js";
13
- import { NARROW_FIRST, STR_METHODS, builtinFenceHintOf, builtinModuleFnOf } from "./surfaces.js";
14
+ import { NARROW_FIRST, STRING_INDEX_METHODS, STR_METHODS, builtinFenceHintOf, builtinModuleFnOf } from "./surfaces.js";
14
15
  import { ffiBindingDiag, ffiSignatureDiag, libCallbackDiag, requiresDynamicDiag } from "../../diagnostics/diagnostic.js";
15
16
  import { mixinFnShapeOf } from "./lower-mixins.js";
16
- import { dynStringReceiver, lowerArrayFromCall, lowerDynArrayFilterCall, lowerDynArrayFlatMapCall, lowerGroupByStaticCall, lowerIteratorHelperCall, lowerObjectAssignIndexShape, lowerObjectFromEntriesCall, lowerObjectIterOverIndexShape, lowerTupleReadMethodCall } from "./lower-containers.js";
17
+ import { dynStringReceiver, lowerArrayConstructor, lowerArrayFromCall, lowerArrayOfCall, lowerDynArrayFilterCall, lowerDynArrayFlatMapCall, lowerGroupByStaticCall, lowerIteratorHelperCall, lowerObjectAssignIndexShape, lowerObjectFromEntriesCall, lowerObjectIterOverIndexShape, lowerTupleReadMethodCall } from "./lower-containers.js";
17
18
  import { bufEncoding } from "./containers/bytes.js";
18
- import { lowerRegexMethodCall, lowerStringMethodCall, lowerStringPaddingCall } from "./containers/string-and-regexp.js";
19
+ import { lowerRegexMethodCall, lowerStringIndexCall, lowerStringMethodCall, lowerStringPaddingCall, lowerStringSplitCall } from "./containers/string-and-regexp.js";
19
20
  import { lowerChildStreamMethodCall, lowerChildWriterMethodCall, lowerCreateRequireCall, lowerCryptoHashMethodCall, lowerDirentMethodCall, lowerFileHandleMethodCall, lowerImportMetaResolveCall, lowerNodeModuleCall, lowerPerfHooksCall, lowerProcStreamMethodCall, lowerReflectApplyCall, lowerRequireResolveCall, lowerWatcherMethodCall } from "./lower-builtins.js";
20
21
  import { lowerAbsenceProbe, lowerPromiseAllTupleCall, lowerPromiseRejectCall, stringWrapperToString, templateRawTextOf } from "./lower-exprs.js";
21
22
  import { isSafeToDiscard } from "./expressions/evaluation-safety.js";
@@ -33,6 +34,7 @@ import { countedFor, varRef } from "../../ir/build.js";
33
34
  import { rejectStaticThis } from "./static-this.js";
34
35
  import { fenceNodeModuleMutationCall, lowerRequireCacheKeys } from "./lower-node-module.js";
35
36
  import { defaultAfterUndefined, lowerOptionalArgument, lowerStaticallyUndefinedArgument, positionNumber } from "./optional-arguments.js";
37
+ export { bodyReadsArguments };
36
38
  /** The one func-type projection of completed parameter shapes. Typed rest
37
39
  * parameters keep their packed array as the trailing native ABI slot and
38
40
  * mark the value variadic so indirect call sites run completeArgs before
@@ -3581,6 +3583,9 @@ export function lowerCall(lowerer, expr) {
3581
3583
  // supported form is fenced here per site. Members with no lowering at
3582
3584
  // all (fs.watch, os.cpus, ...) fence with the module-qualified name.
3583
3585
  if (ts.isIdentifier(expr.expression)) {
3586
+ if (expr.expression.text === "Array" && lowerer.isStdlibGlobal(expr.expression, "Array")) {
3587
+ return lowerArrayConstructor(lowerer, expr, expr.arguments);
3588
+ }
3584
3589
  // A call through a compile-time util.promisify projection. execFile
3585
3590
  // keeps its custom result helper; ordinary builtins route through
3586
3591
  // their existing promise-module lowering.
@@ -4188,6 +4193,8 @@ export function lowerCall(lowerer, expr) {
4188
4193
  // TestContext surface (t.test/t.skip/t.diagnostic), t.assert.*.
4189
4194
  lowerer.lowerTestMethodCall(expr, expr.expression) ??
4190
4195
  lowerer.lowerTimeoutMethodCall(expr, expr.expression) ??
4196
+ lowerObjectOwnPrototypeCall(lowerer, expr, expr.expression) ??
4197
+ lowerObjectPrototypeCall(lowerer, expr, expr.expression) ??
4191
4198
  lowerStringPrototypeCall(lowerer, expr, expr.expression) ??
4192
4199
  lowerStringMethodCallWithOptionalArgs(lowerer, expr, expr.expression) ??
4193
4200
  // Typed-array/Buffer receivers and the Buffer statics — before the
@@ -4217,6 +4224,7 @@ export function lowerCall(lowerer, expr) {
4217
4224
  // hasOwnProperty on a program class CONSTRUCTOR — own statics are
4218
4225
  // compile-time-known, so a literal key folds to a constant.
4219
4226
  lowerClassHasOwnPropertyCall(lowerer, expr, expr.expression) ??
4227
+ lowerObjectOwnMethodCall(lowerer, expr, expr.expression) ??
4220
4228
  // Response constructor-object operations are unsupported in both
4221
4229
  // tiers. Keep their SC2020 inventory contract ahead of the island
4222
4230
  // and generic-call fallbacks (Response.json otherwise reports the
@@ -4257,6 +4265,7 @@ export function lowerCall(lowerer, expr) {
4257
4265
  lowerObjectStaticCall(lowerer, expr, expr.expression) ??
4258
4266
  lowerObjectFromEntriesCall(lowerer, expr, expr.expression) ??
4259
4267
  lowerArrayFromCall(lowerer, expr, expr.expression) ??
4268
+ lowerArrayOfCall(lowerer, expr, expr.expression) ??
4260
4269
  lowerer.lowerArrayMethodCall(expr, expr.expression) ??
4261
4270
  // Read-only array methods (slice/map) on TUPLE receivers — the
4262
4271
  // positions snapshot into a fresh array (the for-of stance).
@@ -4640,6 +4649,243 @@ function plainObjectCoercionReceiver(lowerer, node) {
4640
4649
  return false;
4641
4650
  return bindingNeverReassigned(lowerer, symbol, decl);
4642
4651
  }
4652
+ function objectToStringTag(lowerer, type) {
4653
+ switch (type.kind) {
4654
+ case "undefinedT":
4655
+ case "void": return "Undefined";
4656
+ case "nullT": return "Null";
4657
+ case "bool": return "Boolean";
4658
+ case "f64": return "Number";
4659
+ case "string": return "String";
4660
+ case "bigint": return "BigInt";
4661
+ case "symbol": return "Symbol";
4662
+ case "array": return "Array";
4663
+ case "record": return "Object";
4664
+ case "func":
4665
+ case "classval": return "Function";
4666
+ case "date": return "Date";
4667
+ case "regex": return "RegExp";
4668
+ case "map": return "Map";
4669
+ case "set": return "Set";
4670
+ case "promise": return "Promise";
4671
+ case "bytes":
4672
+ return ({ u8: "Uint8Array", u32: "Uint32Array", i32: "Int32Array", f32: "Float32Array", f64: "Float64Array" })[type.elem];
4673
+ case "object":
4674
+ return type.className === "%Error" || lowerer.isSubclassOf(type.className, "%Error") ? "Error" : null;
4675
+ default: return null;
4676
+ }
4677
+ }
4678
+ function immediateObjectTagReceiver(lowerer, node) {
4679
+ let value = node;
4680
+ while (ts.isParenthesizedExpression(value))
4681
+ value = value.expression;
4682
+ const loc = locOf(value);
4683
+ if (ts.isArrayLiteralExpression(value))
4684
+ return { tag: "Array", effect: lowerer.lowerExpr(value) };
4685
+ if ((ts.isCallExpression(value) || ts.isNewExpression(value)) && ts.isIdentifier(value.expression) &&
4686
+ (value.expression.text === "Array" || value.expression.text === "Error") &&
4687
+ (value.arguments?.length ?? 0) === 0 && lowerer.isStdlibSymbol(lowerer.resolveValueSymbol(value.expression) ?? undefined)) {
4688
+ return { tag: value.expression.text, effect: { kind: "numLit", value: 0, type: F64, loc } };
4689
+ }
4690
+ if (ts.isNewExpression(value) && ts.isIdentifier(value.expression) &&
4691
+ lowerer.isStdlibSymbol(lowerer.resolveValueSymbol(value.expression) ?? undefined)) {
4692
+ const name = value.expression.text;
4693
+ const args = value.arguments ?? [];
4694
+ if (args.length <= 1 && !args.some(ts.isSpreadElement)) {
4695
+ if (name === "String") {
4696
+ const effect = stringWrapperToString(lowerer, value);
4697
+ if (effect)
4698
+ return { tag: "String", effect };
4699
+ }
4700
+ if (name === "Number")
4701
+ return {
4702
+ tag: "Number",
4703
+ effect: args.length ? lowerNumberConstructorValue(lowerer, args[0], loc) : { kind: "numLit", value: 0, type: F64, loc },
4704
+ };
4705
+ if (name === "Boolean")
4706
+ return {
4707
+ tag: "Boolean",
4708
+ effect: args.length ? lowerer.lowerCondition(args[0]) : { kind: "boolLit", value: false, type: BOOL, loc },
4709
+ };
4710
+ }
4711
+ }
4712
+ if ((ts.isCallExpression(value) || ts.isNewExpression(value)) &&
4713
+ ts.isIdentifier(value.expression) && value.expression.text === "Object" &&
4714
+ lowerer.isStdlibSymbol(lowerer.resolveValueSymbol(value.expression) ?? undefined)) {
4715
+ const args = value.arguments ?? [];
4716
+ if (args.some(ts.isSpreadElement))
4717
+ return null;
4718
+ const first = args[0];
4719
+ const inner = first && (immediateObjectTagReceiver(lowerer, first) ?? (() => {
4720
+ const effect = lowerer.lowerExpr(first);
4721
+ const tag = isUnitType(effect.type) || effect.type.kind === "void" ? "Object" : objectToStringTag(lowerer, effect.type);
4722
+ return tag === null ? null : { tag, effect };
4723
+ })());
4724
+ if (first && !inner)
4725
+ return null;
4726
+ const stmts = [];
4727
+ if (inner && !isSafeToDiscard(inner.effect))
4728
+ stmts.push({ kind: "exprStmt", expr: inner.effect, loc: inner.effect.loc });
4729
+ for (const extra of args.slice(1)) {
4730
+ const effect = lowerer.lowerExpr(extra);
4731
+ if (!isSafeToDiscard(effect))
4732
+ stmts.push({ kind: "exprStmt", expr: effect, loc: locOf(extra) });
4733
+ }
4734
+ return {
4735
+ tag: inner?.tag ?? "Object",
4736
+ effect: { kind: "seqExpr", stmts, result: { kind: "numLit", value: 0, type: F64, loc }, type: F64, loc },
4737
+ };
4738
+ }
4739
+ return null;
4740
+ }
4741
+ function lowerObjectOwnPrototypeCall(lowerer, call, access) {
4742
+ if (lowerer.dynamic || access.name.text !== "call" || !ts.isPropertyAccessExpression(access.expression))
4743
+ return null;
4744
+ const method = access.expression;
4745
+ const enumerable = method.name.text === "propertyIsEnumerable";
4746
+ if (method.name.text !== "hasOwnProperty" && !enumerable)
4747
+ return null;
4748
+ const prototype = method.expression;
4749
+ if (!ts.isPropertyAccessExpression(prototype) || prototype.name.text !== "prototype" ||
4750
+ !lowerer.isStdlibGlobal(prototype.expression, "Object") || !lowerer.isStdlibMember(method) ||
4751
+ call.arguments.some(ts.isSpreadElement))
4752
+ return null;
4753
+ return lowerObjectOwnCall(lowerer, call, call.arguments[0], call.arguments[1], call.arguments.slice(2), method.name.text);
4754
+ }
4755
+ function lowerObjectOwnMethodCall(lowerer, call, access) {
4756
+ const method = access.name.text;
4757
+ if (lowerer.dynamic || call.questionDotToken || access.questionDotToken ||
4758
+ (method !== "hasOwnProperty" && method !== "propertyIsEnumerable") ||
4759
+ !lowerer.isStdlibMember(access) || call.arguments.some(ts.isSpreadElement))
4760
+ return null;
4761
+ return lowerObjectOwnCall(lowerer, call, access.expression, call.arguments[0], call.arguments.slice(1), method);
4762
+ }
4763
+ function lowerObjectOwnCall(lowerer, call, receiverNode, keyNode, extraNodes, method) {
4764
+ const enumerable = method === "propertyIsEnumerable";
4765
+ const loc = locOf(call);
4766
+ const stmts = [];
4767
+ const receiver = receiverNode ? lowerer.lowerExpr(receiverNode) : { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc };
4768
+ let receiverRef = receiver;
4769
+ if (isUnitType(receiver.type) || receiver.type.kind === "void") {
4770
+ if (!isSafeToDiscard(receiver))
4771
+ stmts.push({ kind: "exprStmt", expr: receiver, loc });
4772
+ }
4773
+ else {
4774
+ const local = lowerer.declareHiddenLocal("%ownReceiver", receiver.type);
4775
+ stmts.push({ kind: "varDecl", localId: local.id, init: receiver, loc });
4776
+ receiverRef = varRef(local.id, receiver.type, loc);
4777
+ }
4778
+ const rawKey = keyNode ? lowerer.lowerExpr(keyNode) : null;
4779
+ let keyRef = rawKey;
4780
+ if (rawKey && (isUnitType(rawKey.type) || rawKey.type.kind === "void")) {
4781
+ if (!isSafeToDiscard(rawKey))
4782
+ stmts.push({ kind: "exprStmt", expr: rawKey, loc: rawKey.loc });
4783
+ }
4784
+ else if (rawKey) {
4785
+ const local = lowerer.declareHiddenLocal("%ownKey", rawKey.type);
4786
+ stmts.push({ kind: "varDecl", localId: local.id, init: rawKey, loc: rawKey.loc });
4787
+ keyRef = varRef(local.id, rawKey.type, loc);
4788
+ }
4789
+ for (const extra of extraNodes) {
4790
+ const effect = lowerer.lowerExpr(extra);
4791
+ if (!isSafeToDiscard(effect))
4792
+ stmts.push({ kind: "exprStmt", expr: effect, loc: locOf(extra) });
4793
+ }
4794
+ let key = keyRef;
4795
+ if (!keyNode || rawKey?.type.kind === "undefinedT" || rawKey?.type.kind === "void") {
4796
+ key = { kind: "strLit", value: "undefined", type: STRING, loc };
4797
+ }
4798
+ else if (rawKey?.type.kind === "nullT") {
4799
+ key = { kind: "strLit", value: "null", type: STRING, loc };
4800
+ }
4801
+ else if (key && (key.type.kind === "f64" || key.type.kind === "bool" || key.type.kind === "bigint")) {
4802
+ key = { kind: "toString", operand: key, type: STRING, loc };
4803
+ }
4804
+ if (!key || key.type.kind !== "string") {
4805
+ lowerer.noLowering("Object.prototype." + method + " with this property key", keyNode ?? call);
4806
+ }
4807
+ let result;
4808
+ const type = receiver.type;
4809
+ if (isUnitType(type) || type.kind === "void") {
4810
+ result = nodeThrowExpr(1, "", "Cannot convert undefined or null to object", BOOL, loc);
4811
+ }
4812
+ else if (type.kind === "record") {
4813
+ const shape = lowerer.shapes.get(type.shapeId);
4814
+ if (!shape || shape.tuple || shape.indexValue || shapeHasAccessorSlots(shape)) {
4815
+ lowerer.noLowering("Object.prototype." + method + " over this record shape", receiverNode ?? call);
4816
+ }
4817
+ result = { kind: "call", callee: recordHasOwnHelper(lowerer, type.shapeId, loc), args: [receiverRef, key], type: BOOL, loc };
4818
+ }
4819
+ else if (type.kind === "dyn" && !enumerable) {
4820
+ result = { kind: "libCall", fn: "dyn.hasOwn", args: [receiverRef, key], type: BOOL, loc };
4821
+ }
4822
+ else if (type.kind === "string" || type.kind === "array") {
4823
+ const needleLocal = lowerer.declareHiddenLocal("%ownIndex", F64);
4824
+ stmts.push({ kind: "varDecl", localId: needleLocal.id, init: { kind: "libCall", fn: "num.fromString", args: [key], type: F64, loc }, loc });
4825
+ const needle = varRef(needleLocal.id, F64, loc);
4826
+ const length = type.kind === "string"
4827
+ ? { kind: "strIntrinsic", method: "length", receiver: receiverRef, args: [], type: F64, loc }
4828
+ : { kind: "arrIntrinsic", method: "length", receiver: receiverRef, args: [], type: F64, loc };
4829
+ const inRange = { kind: "bin", op: "<", left: needle, right: length, type: BOOL, loc };
4830
+ const nonNegative = { kind: "bin", op: ">=", left: needle, right: { kind: "numLit", value: 0, type: F64, loc }, type: BOOL, loc };
4831
+ const integer = { kind: "bin", op: "===", left: needle,
4832
+ right: { kind: "libCall", fn: "math.floor", args: [needle], type: F64, loc }, type: BOOL, loc };
4833
+ const canonical = { kind: "strEq", negated: false, left: key, right: { kind: "toString", operand: needle, type: STRING, loc }, type: BOOL, loc };
4834
+ const present = type.kind === "string" ? { kind: "boolLit", value: true, type: BOOL, loc } :
4835
+ { kind: "bin", op: "===", left: { kind: "arrIntrinsic", method: "nextPresent", receiver: receiverRef, args: [needle], type: F64, loc }, right: needle, type: BOOL, loc };
4836
+ const no = { kind: "boolLit", value: false, type: BOOL, loc };
4837
+ const indexOwn = [inRange, integer, canonical, present].reduce((left, right) => ({ kind: "logical", op: "&&", left, right, type: BOOL, loc }), nonNegative);
4838
+ const lengthOwn = !enumerable
4839
+ ? { kind: "strEq", negated: false, left: key, right: { kind: "strLit", value: "length", type: STRING, loc }, type: BOOL, loc }
4840
+ : no;
4841
+ result = { kind: "logical", op: "||", left: lengthOwn, right: indexOwn, type: BOOL, loc };
4842
+ }
4843
+ else if (type.kind === "f64" || type.kind === "bool" || type.kind === "bigint" || type.kind === "symbol") {
4844
+ result = { kind: "boolLit", value: false, type: BOOL, loc };
4845
+ }
4846
+ else {
4847
+ lowerer.noLowering("Object.prototype." + method + " over a " + lowerer.fmt(type) + " receiver", receiverNode ?? call);
4848
+ }
4849
+ return { kind: "seqExpr", stmts, result, type: BOOL, loc };
4850
+ }
4851
+ function lowerObjectPrototypeCall(lowerer, call, access) {
4852
+ if (lowerer.dynamic || access.name.text !== "call" || !ts.isPropertyAccessExpression(access.expression))
4853
+ return null;
4854
+ const method = access.expression;
4855
+ const prototype = method.expression;
4856
+ if (method.name.text !== "toString" || !ts.isPropertyAccessExpression(prototype) ||
4857
+ prototype.name.text !== "prototype" || !lowerer.isStdlibGlobal(prototype.expression, "Object") ||
4858
+ !lowerer.isStdlibMember(method) || call.arguments.some(ts.isSpreadElement))
4859
+ return null;
4860
+ const loc = locOf(call);
4861
+ if (call.arguments.length === 0)
4862
+ return { kind: "strLit", value: "[object Undefined]", type: STRING, loc };
4863
+ const receiverNode = call.arguments[0];
4864
+ const immediate = immediateObjectTagReceiver(lowerer, receiverNode);
4865
+ const receiver = immediate?.effect ?? lowerer.lowerExpr(receiverNode);
4866
+ const tag = immediate?.tag ?? objectToStringTag(lowerer, receiver.type);
4867
+ if (tag === null && receiver.type.kind !== "dyn") {
4868
+ lowerer.noLowering("Object.prototype.toString.call over a " + lowerer.fmt(receiver.type) + " receiver", receiverNode);
4869
+ }
4870
+ const stmts = [];
4871
+ let ref = receiver;
4872
+ if (isUnitType(receiver.type) || receiver.type.kind === "void") {
4873
+ if (!isSafeToDiscard(receiver))
4874
+ stmts.push({ kind: "exprStmt", expr: receiver, loc });
4875
+ }
4876
+ else {
4877
+ const local = lowerer.declareHiddenLocal("%objectTagReceiver", receiver.type);
4878
+ stmts.push({ kind: "varDecl", localId: local.id, init: receiver, loc });
4879
+ ref = varRef(local.id, receiver.type, loc);
4880
+ }
4881
+ for (const extra of call.arguments.slice(1)) {
4882
+ stmts.push({ kind: "exprStmt", expr: lowerer.lowerExpr(extra), loc: locOf(extra) });
4883
+ }
4884
+ const result = tag === null
4885
+ ? { kind: "libCall", fn: "dyn.objectTag", args: [ref], type: STRING, loc }
4886
+ : { kind: "strLit", value: "[object " + tag + "]", type: STRING, loc };
4887
+ return { kind: "seqExpr", stmts, result, type: STRING, loc };
4888
+ }
4643
4889
  function lowerStringPrototypeCall(lowerer, call, access) {
4644
4890
  if (access.name.text !== "call" || !ts.isPropertyAccessExpression(access.expression))
4645
4891
  return null;
@@ -4647,21 +4893,26 @@ function lowerStringPrototypeCall(lowerer, call, access) {
4647
4893
  const prototypeAccess = methodAccess.expression;
4648
4894
  if (!ts.isPropertyAccessExpression(prototypeAccess) || prototypeAccess.name.text !== "prototype" ||
4649
4895
  !ts.isIdentifier(prototypeAccess.expression) || prototypeAccess.expression.text !== "String" ||
4650
- !Object.hasOwn(STR_METHODS, methodAccess.name.text) || !lowerer.isStdlibMember(methodAccess))
4896
+ (!Object.hasOwn(STR_METHODS, methodAccess.name.text) && !STRING_INDEX_METHODS.has(methodAccess.name.text)) ||
4897
+ !lowerer.isStdlibMember(methodAccess))
4651
4898
  return null;
4652
4899
  if (call.arguments.some(ts.isSpreadElement))
4653
4900
  return null;
4654
4901
  const entry = STR_METHODS[methodAccess.name.text];
4902
+ const indexMethod = STRING_INDEX_METHODS.has(methodAccess.name.text) ? methodAccess.name.text : null;
4903
+ const resultType = indexMethod ? lowerer.withUndefinedArmOf(indexMethod === "at" ? STRING : F64) : entry?.result;
4904
+ if (!resultType)
4905
+ return null;
4655
4906
  const method = methodAccess.name.text === "trimStart" ? "trimLeft" :
4656
4907
  methodAccess.name.text === "trimEnd" ? "trimRight" : methodAccess.name.text;
4657
4908
  const loc = locOf(call);
4658
- const nullishError = nodeThrowExpr(1, "", `String.prototype.${method} called on null or undefined`, entry.result, loc);
4909
+ const nullishError = nodeThrowExpr(1, "", `String.prototype.${method} called on null or undefined`, resultType, loc);
4659
4910
  const receiverNode = call.arguments[0];
4660
4911
  if (!receiverNode)
4661
4912
  return nullishError;
4662
4913
  // Receiver coercion runs after .call has evaluated its arguments; keep
4663
4914
  // contextual wrapper lowering on forms without later method arguments.
4664
- const immediateWrapper = entry.maxArgs === 0 && call.arguments.length === 1
4915
+ const immediateWrapper = entry?.maxArgs === 0 && call.arguments.length === 1
4665
4916
  ? immediatePrimitiveWrapperToString(lowerer, receiverNode) : null;
4666
4917
  const receiverValue = immediateWrapper ?? lowerer.lowerExpr(receiverNode);
4667
4918
  const receiverType = receiverValue.type;
@@ -4673,26 +4924,33 @@ function lowerStringPrototypeCall(lowerer, call, access) {
4673
4924
  kind: "seqExpr",
4674
4925
  stmts: values.filter((value) => !isSafeToDiscard(value)).map((value) => ({ kind: "exprStmt", expr: value, loc: value.loc })),
4675
4926
  result: nullishError,
4676
- type: entry.result,
4927
+ type: resultType,
4677
4928
  loc,
4678
4929
  };
4679
4930
  }
4680
- const padding = entry.method === "padStart" || entry.method === "padEnd";
4931
+ const padding = entry?.method === "padStart" || entry?.method === "padEnd";
4681
4932
  const scalar = receiverType.kind === "string" || receiverType.kind === "f64" ||
4682
4933
  receiverType.kind === "bool" || receiverType.kind === "bigint" ||
4683
4934
  (receiverType.kind === "union" && (lowerer.unions.get(receiverType.unionId)?.arms.every((arm) => arm.kind === "string" || arm.kind === "f64" || arm.kind === "bool" || arm.kind === "bigint") ?? false));
4684
4935
  // Other methods convert object receivers before lowering their arguments;
4685
4936
  // padding uses a helper that delays conversion until every argument is ready.
4686
- const objectWithoutMethodArgs = entry.maxArgs === 0 && call.arguments.length === 1 &&
4937
+ const objectWithoutMethodArgs = entry?.maxArgs === 0 && call.arguments.length === 1 &&
4687
4938
  (receiverType.kind === "record" || receiverType.kind === "array" || receiverType.kind === "object");
4688
- const dynObjectWithoutMethodArgs = entry.maxArgs === 0 && call.arguments.length === 1 &&
4939
+ const dynObjectWithoutMethodArgs = entry?.maxArgs === 0 && call.arguments.length === 1 &&
4689
4940
  receiverType.kind === "dyn" && plainObjectCoercionReceiver(lowerer, receiverNode);
4690
4941
  if (!scalar && !objectWithoutMethodArgs && !dynObjectWithoutMethodArgs && !(padding && receiverType.kind === "dyn")) {
4691
4942
  return lowerer.noLowering(`String.prototype.${methodAccess.name.text}.call with ${lowerer.fmt(receiverType)} receivers`, call);
4692
4943
  }
4944
+ if (indexMethod)
4945
+ return lowerStringIndexCall(lowerer, call, indexMethod, receiverValue, receiverNode, call.arguments.slice(1));
4946
+ if (!entry)
4947
+ return null;
4693
4948
  if (padding) {
4694
4949
  return lowerStringPaddingCall(lowerer, call, entry.method, receiverValue, receiverNode, call.arguments.slice(1));
4695
4950
  }
4951
+ if (entry.method === "split") {
4952
+ return lowerStringSplitCall(lowerer, call, receiverValue, receiverNode, call.arguments.slice(1));
4953
+ }
4696
4954
  const receiver = dynObjectWithoutMethodArgs
4697
4955
  ? { kind: "libCall", fn: "dyn.toStringCoerce", args: [receiverValue], type: STRING, loc }
4698
4956
  : lowerer.ensureString(receiverValue, receiverNode);
@@ -6093,31 +6351,6 @@ export function lambdaSignature(lowerer, node) {
6093
6351
  funcType.rest = true;
6094
6352
  return { shapes, funcType };
6095
6353
  }
6096
- /** Does this function's OWN body read `arguments`? Nested plain functions
6097
- * and methods have their own `arguments` (the walk skips them); arrows
6098
- * see the enclosing one (the walk descends). Exported for the lowerer's
6099
- * dynFallbackType: tsgo does not synthesize the `arguments` rest
6100
- * parameter into inferred signatures (5.9.3 did — its param-count
6101
- * mismatch was the detector), so the 7 world asks the BODY directly. */
6102
- export function bodyReadsArguments(fn) {
6103
- let found = false;
6104
- if (fn.body === undefined)
6105
- return false;
6106
- // Iterative walk (walkPreorder): function bodies can hold pathologically
6107
- // deep expression chains that a recursive visit would die on.
6108
- ts.walkPreorder(fn.body, (n) => {
6109
- if (ts.isIdentifier(n) && n.text === "arguments" && !(ts.isPropertyAccessExpression(n.parent) && n.parent.name === n)) {
6110
- found = true;
6111
- return "stop";
6112
- }
6113
- if ((ts.isFunctionExpression(n) || ts.isFunctionDeclaration(n) || ts.isMethodDeclaration(n)) &&
6114
- n !== fn) {
6115
- return "skip"; // own `arguments` scope
6116
- }
6117
- return undefined;
6118
- });
6119
- return found;
6120
- }
6121
6354
  /** Lifts an arrow function / function expression / nested declaration /
6122
6355
  * object-literal shorthand method to a module-level function and yields
6123
6356
  * the `closure` expression creating it. */
@@ -6313,9 +6546,8 @@ export function lowerLambda(lowerer, node) {
6313
6546
  * becomes the catch binding, and a handler VALUE would need a
6314
6547
  * caught-typed closure parameter, which cannot exist. finally takes
6315
6548
  * any () => void closure (its callback sees no arguments). then takes
6316
- * exactly one FULFILLMENT handler (any closure value of the settled
6317
- * value's type — the two-argument onRejected form stays fenced toward
6318
- * .catch); a promise-returning handler flattens through the async
6549
+ * a fulfillment handler and optionally a rejection handler; a
6550
+ * promise-returning handler flattens through the async
6319
6551
  * return path, a receiver rejection passes through untouched (the
6320
6552
  * wrapper's await re-throws it), and a handler throw rejects the
6321
6553
  * result — the spec's onFulfilled rules by construction. Null for
@@ -6414,9 +6646,9 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
6414
6646
  };
6415
6647
  const passthrough = call.arguments.length === 0 ||
6416
6648
  (call.arguments.length === 1 && isAbsentHandler(call.arguments[0]));
6417
- if (call.arguments.length !== 1 && !passthrough) {
6649
+ if (call.arguments.length !== 1 && !passthrough && !(member === "then" && call.arguments.length === 2)) {
6418
6650
  lowerer.noLowering(`${member} with ${call.arguments.length} arguments`, call, member === "then"
6419
- ? "the supported form takes exactly one fulfillment handler — chain .catch(...) for the rejection half"
6651
+ ? "the supported form takes a fulfillment handler and an optional rejection handler"
6420
6652
  : `the supported form takes exactly one ${member === "catch" ? "inline handler" : "callback"}`);
6421
6653
  }
6422
6654
  // The receiver evaluates FIRST, in the enclosing function, like JS.
@@ -6488,6 +6720,140 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
6488
6720
  }
6489
6721
  }
6490
6722
  if (member === "then") {
6723
+ if (call.arguments.length === 2) {
6724
+ const fulfilledNode = call.arguments[0];
6725
+ const rejectedNode = call.arguments[1];
6726
+ const fulfilledAbsent = isAbsentHandler(fulfilledNode);
6727
+ const rejectedAbsent = isAbsentHandler(rejectedNode);
6728
+ const resultT = lowerer.mapTypeOf(lowerer.typeOf(call));
6729
+ if (resultT?.kind !== "promise") {
6730
+ lowerer.noLowering("then with these handlers", call, "the result must be a representable promise");
6731
+ }
6732
+ const R = resultT.inner;
6733
+ if (!fulfilledAbsent && inner.kind === "jsval")
6734
+ markJsvalHandlerParams(lowerer, fulfilledNode);
6735
+ if (!fulfilledAbsent && inner.kind === "moduleNs")
6736
+ markModuleNsHandlerParams(lowerer, fulfilledNode, inner);
6737
+ const boxHandler = (node, allowDirect) => {
6738
+ const value = lowerer.lowerExpr(node);
6739
+ if (allowDirect && value.type.kind === "func" && value.type.params.length <= 1 &&
6740
+ (value.type.params.length === 0 || (inner.kind !== "void" && typeEquals(value.type.params[0], inner)))) {
6741
+ return { value, direct: true, returnsPromise: value.type.ret.kind === "promise" };
6742
+ }
6743
+ if (value.type.kind === "dyn")
6744
+ return { value, direct: false, returnsPromise: false };
6745
+ if (value.type.kind === "func" && value.type.params.length <= 1 &&
6746
+ canBoxFuncIntoDyn(value.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
6747
+ return { value: { kind: "dynFrom", value, type: DYN, loc }, direct: false, returnsPromise: value.type.ret.kind === "promise" };
6748
+ }
6749
+ lowerer.unsupported("SC1090", node, "then handlers that cannot be called with one value");
6750
+ };
6751
+ // Evaluate both callback expressions before the wrapper runs, in source order.
6752
+ const fulfilled = fulfilledAbsent ? null : boxHandler(fulfilledNode, true);
6753
+ const rejected = rejectedAbsent ? null : boxHandler(rejectedNode, false);
6754
+ const fnName = `%fn${lowerer.lambdaCounter++}_then2`;
6755
+ const paramTypes = [promT, ...(fulfilled ? [fulfilled.value.type] : []), ...(rejected ? [DYN] : [])];
6756
+ const funcType = { kind: "func", params: paramTypes, ret: resultT };
6757
+ const fnCtx = newFnCtx(true, null, funcType, R);
6758
+ fnCtx.isAsync = true;
6759
+ lowerer.fnStack.push(fnCtx);
6760
+ try {
6761
+ const pLocal = lowerer.declareHiddenLocal("p", promT);
6762
+ const fLocal = fulfilled ? lowerer.declareHiddenLocal("f", fulfilled.value.type) : null;
6763
+ const rLocal = rejected ? lowerer.declareHiddenLocal("r", DYN) : null;
6764
+ const eLocal = lowerer.declareHiddenLocal("e", CAUGHT);
6765
+ const vLocal = inner.kind === "void" ? null : lowerer.declareHiddenLocal("v", inner);
6766
+ const awaitE = {
6767
+ kind: "awaitExpr",
6768
+ value: { kind: "varRef", localId: pLocal.id, type: promT, loc },
6769
+ type: inner,
6770
+ loc,
6771
+ };
6772
+ const tryBody = vLocal
6773
+ ? [{ kind: "varDecl", localId: vLocal.id, init: awaitE, loc }]
6774
+ : [{ kind: "exprStmt", expr: awaitE, loc }];
6775
+ const resultOf = (value, returnsPromise = false) => {
6776
+ const settled = value.type.kind === "promise"
6777
+ ? { kind: "awaitExpr", value, type: value.type.inner, loc }
6778
+ : returnsPromise
6779
+ ? { kind: "libCall", fn: "async.awaitDyn", args: [value], type: DYN, loc }
6780
+ : value;
6781
+ return R.kind === "void"
6782
+ ? [{ kind: "exprStmt", expr: settled, loc }, { kind: "return", value: null, loc }]
6783
+ : [{ kind: "return", value: lowerer.coerceInto(call, settled, R), loc }];
6784
+ };
6785
+ const rejectedCall = rLocal ? {
6786
+ kind: "dynCall",
6787
+ callee: { kind: "varRef", localId: rLocal.id, type: DYN, loc },
6788
+ calleeName: jsFuncNameOf(rejectedNode) ?? "onRejected",
6789
+ args: [{ kind: "caughtToDyn", value: { kind: "varRef", localId: eLocal.id, type: CAUGHT, loc }, type: DYN, loc }],
6790
+ type: DYN,
6791
+ loc,
6792
+ } : null;
6793
+ const catchBody = rejectedCall
6794
+ ? resultOf(rejectedCall, rejected?.returnsPromise)
6795
+ : [{ kind: "rethrow", localId: eLocal.id, loc }];
6796
+ const body = [{ kind: "tryCatch", tryBody, catchBody, catchLocalId: eLocal.id, finallyBody: null, loc }];
6797
+ // The fulfillment callback sits after the catch so a throw from it
6798
+ // rejects the result instead of reaching onRejected.
6799
+ if (fLocal) {
6800
+ const settled = vLocal
6801
+ ? { kind: "varRef", localId: vLocal.id, type: inner, loc }
6802
+ : dynUndefinedExpr(loc);
6803
+ if (fulfilled.direct && fLocal.type.kind === "func") {
6804
+ body.push(...resultOf({
6805
+ kind: "callValue",
6806
+ callee: { kind: "varRef", localId: fLocal.id, type: fLocal.type, loc },
6807
+ args: fLocal.type.params.length === 0 ? [] : [settled],
6808
+ type: fLocal.type.ret,
6809
+ loc,
6810
+ }));
6811
+ }
6812
+ else {
6813
+ const arg = settled.type.kind === "dyn" ? settled
6814
+ : canConvertToDyn(settled.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))
6815
+ ? { kind: "dynFrom", value: settled, type: DYN, loc }
6816
+ : lowerer.unsupported("SC1090", fulfilledNode, "then fulfillment values that cannot cross the checked-dynamic boundary");
6817
+ body.push(...resultOf({
6818
+ kind: "dynCall",
6819
+ callee: { kind: "varRef", localId: fLocal.id, type: DYN, loc },
6820
+ calleeName: jsFuncNameOf(fulfilledNode) ?? "onFulfilled",
6821
+ args: [arg], type: DYN, loc,
6822
+ }, fulfilled?.returnsPromise));
6823
+ }
6824
+ }
6825
+ else if (vLocal) {
6826
+ body.push(...resultOf({ kind: "varRef", localId: vLocal.id, type: inner, loc }));
6827
+ }
6828
+ else if (R.kind === "void") {
6829
+ body.push({ kind: "return", value: null, loc });
6830
+ }
6831
+ else {
6832
+ body.push({ kind: "return", value: lowerer.coerceInto(call, dynUndefinedExpr(loc), R), loc });
6833
+ }
6834
+ const ctx = lowerer.ctx;
6835
+ const lifted = {
6836
+ name: fnName,
6837
+ params: [
6838
+ { localId: pLocal.id, name: pLocal.name, type: promT },
6839
+ ...(fLocal ? [{ localId: fLocal.id, name: fLocal.name, type: fLocal.type }] : []),
6840
+ ...(rLocal ? [{ localId: rLocal.id, name: rLocal.name, type: DYN }] : []),
6841
+ ],
6842
+ returnType: R,
6843
+ locals: ctx.locals,
6844
+ captures: ctx.captures,
6845
+ body,
6846
+ loc,
6847
+ async: true,
6848
+ };
6849
+ lowerer.liftedFns.push(lifted);
6850
+ const closure = { kind: "closure", fnName, captures: ctx.captureSources, type: funcType, loc };
6851
+ return { kind: "callValue", callee: closure, args: [receiver, ...(fulfilled ? [fulfilled.value] : []), ...(rejected ? [rejected.value] : [])], type: resultT, loc };
6852
+ }
6853
+ finally {
6854
+ lowerer.fnStack.pop();
6855
+ }
6856
+ }
6491
6857
  // The settled value is an island HANDLE: an inline handler's
6492
6858
  // unannotated parameter binds it as jsval, whatever the checker's
6493
6859
  // contextual type spelled (a module-namespace type has no mapping —