@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
@@ -0,0 +1,117 @@
1
+ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { expect, test } from "vitest";
5
+ import { checkPreflight, loadProgram } from "./program.js";
6
+ function requireOrderDiagnostics(source, dependency = "exports.value = 'ready';\n") {
7
+ const dir = mkdtempSync(join(tmpdir(), "scriptc-require-order-"));
8
+ const entry = join(dir, "main.cjs");
9
+ writeFileSync(entry, source);
10
+ writeFileSync(join(dir, "dep.cjs"), dependency);
11
+ const load = loadProgram(entry);
12
+ try {
13
+ return checkPreflight(load);
14
+ }
15
+ finally {
16
+ load.dispose();
17
+ rmSync(dir, { recursive: true, force: true });
18
+ }
19
+ }
20
+ test.for([
21
+ "exports.read = read;",
22
+ "module.exports.renamed = read;",
23
+ "module.exports = read;",
24
+ ])("a hoisted function export before require is safe: %s", (publish) => {
25
+ expect(requireOrderDiagnostics(`
26
+ 'use strict';
27
+ Object.defineProperty(exports, '__esModule', { value: true });
28
+ ${publish}
29
+ const dep = require('./dep.cjs');
30
+ function read() { return helper(); }
31
+ function helper() { return dep.value; }
32
+ `)).toEqual([]);
33
+ });
34
+ test.for([
35
+ "exports.a = exports.b = void 0;",
36
+ "exports.a = undefined; exports.b = 'literal'; exports.c = 1;",
37
+ "exports.first = exports.second = read;",
38
+ ])("literal and chained export prologues do not invoke functions: %s", (prefix) => {
39
+ expect(requireOrderDiagnostics(`
40
+ Object.defineProperty(exports, '__esModule', { value: true });
41
+ ${prefix}
42
+ exports.read = read;
43
+ const dep = require('./dep.cjs');
44
+ function read() { return dep.value; }
45
+ `)).toEqual([]);
46
+ });
47
+ test.for([
48
+ ["direct call", "read();"],
49
+ ["transitive call", "helper(); function helper() { return read(); }"],
50
+ ["callback escape", "[1].map(read);"],
51
+ ["export call", "exports.read();"],
52
+ ["export alias call", "const alias = exports; alias.read();"],
53
+ ["computed export name", "exports[read()] = read;"],
54
+ ["export initializer call", "exports.value = read();"],
55
+ ["class static initializer", "class Early { static value = read(); }"],
56
+ ["extra descriptor effect", "Object.defineProperty(exports, '__esModule', { value: true, enumerable: read() });"],
57
+ ["void initializer call", "exports.value = void read();"],
58
+ ["prototype mutation", "exports.__proto__ = read;"],
59
+ ["read-only marker", "Object.defineProperty(exports, '__esModule', { value: true }); exports.__esModule = read;"],
60
+ ["replacement export property", "module.exports = read; module.exports.name = read;"],
61
+ ["non-export assignment chain", "const box = {}; exports.alias = box.read = read;"],
62
+ ])("require still refuses an early read through %s", ([, early]) => {
63
+ const diagnostics = requireOrderDiagnostics(`
64
+ exports.read = read;
65
+ ${early}
66
+ const dep = require('./dep.cjs');
67
+ function read() { return dep.value; }
68
+ `);
69
+ expect(diagnostics.some((diag) => diag.code === "SC1013" && diag.message.includes("binding 'dep'")))
70
+ .toBe(true);
71
+ });
72
+ test("publishing a require binding itself still reads it before initialization", () => {
73
+ const diagnostics = requireOrderDiagnostics(`
74
+ exports.read = read;
75
+ const { read } = require('./dep.cjs');
76
+ `);
77
+ expect(diagnostics.some((diag) => diag.code === "SC1013" && diag.message.includes("binding 'read'")))
78
+ .toBe(true);
79
+ });
80
+ test.for([
81
+ "var Object = null; Object.defineProperty(exports, '__esModule', { value: true }); exports.read = read;",
82
+ "var exports = null; exports.read = read;",
83
+ "var module = null; module.exports = read;",
84
+ ])("source bindings cannot masquerade as a CommonJS prologue: %s", (prefix) => {
85
+ const diagnostics = requireOrderDiagnostics(`
86
+ ${prefix}
87
+ const dep = require('./dep.cjs');
88
+ function read() { return dep.value; }
89
+ `);
90
+ expect(diagnostics.some((diag) => diag.code === "SC1013" && diag.message.includes("binding 'dep'")))
91
+ .toBe(true);
92
+ });
93
+ test("an earlier declarator can call an export before the require initializes", () => {
94
+ const diagnostics = requireOrderDiagnostics(`
95
+ exports.read = read;
96
+ const before = read(), dep = require('./dep.cjs');
97
+ function read() { return dep.value; }
98
+ `);
99
+ expect(diagnostics.some((diag) => diag.code === "SC1013" && diag.message.includes("binding 'dep'")))
100
+ .toBe(true);
101
+ });
102
+ test("a later declarator can call an export after the require initializes", () => {
103
+ expect(requireOrderDiagnostics(`
104
+ exports.read = read;
105
+ const dep = require('./dep.cjs'), after = read();
106
+ function read() { return dep.value; }
107
+ `)).toEqual([]);
108
+ });
109
+ test("function publication does not admit CommonJS cycles", () => {
110
+ const diagnostics = requireOrderDiagnostics(`
111
+ exports.read = read;
112
+ const dep = require('./dep.cjs');
113
+ function read() { return dep.value; }
114
+ `, "const main = require('./main.cjs'); exports.value = main.read();\n");
115
+ expect(diagnostics.some((diag) => diag.code === "SC1016")).toBe(true);
116
+ });
117
+ //# sourceMappingURL=program.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"program.test.js","sourceRoot":"","sources":["../../src/frontend/program.test.ts"],"names":[],"mappings":"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"}
@@ -155,8 +155,10 @@ export declare class UnionRegistry {
155
155
  }
156
156
  /** Human-readable rendering of an IrType for diagnostics (records expand to
157
157
  * their canonical field list, unions to their arms; `checker.typeToString`
158
- * can't — it never sees IR types). `seen` breaks recursive shapes/unions:
159
- * a back-reference renders as "..." instead of expanding forever. */
158
+ * can't — it never sees IR types). Bound the traversal as well as its output:
159
+ * cycle detection alone still expands a shared acyclic graph exponentially.
160
+ * The same budget covers every sibling, and deep wrapper chains truncate
161
+ * before exhausting the JS stack. Small types retain their full spelling. */
160
162
  export declare function formatIrType(t: IrType, shapes: ShapeRegistry, unions: UnionRegistry, seen?: Set<string>): string;
161
163
  /** True when a type contains a record anywhere (the trigger for the
162
164
  * shape-mismatch diagnostic SC2002 — non-record mismatches are tsc's or
@@ -1,5 +1,6 @@
1
1
  import { InternalCompilerError } from "../errors.js";
2
2
  import * as ts from "./ts7/adapter.js";
3
+ import { bodyReadsArguments } from "./arguments-usage.js";
3
4
  import { arrayOf, BOOL, bytesOf, canConvertToDyn, CHILD_T, CRYPTOHASH_T, CRYPTOHMAC_T, DATE_T, DYN, F64, funcOf, isSupportedArrayElem, isSupportedIndexValue, isSupportedMapKey, isSupportedMapValue, isSupportedSetElem, isUnitType, JSVAL, mapOf, NULL_T, PROCSTREAM_T, RUNTIME_EMITTER_CLASS, RUNTIME_ERROR_CLASSES, RUNTIME_STREAM_CLASSES, setOf, STRING, SYMBOL_T, typeEquals, typeKey, UNDEFINED_T, VOID } from "../ir/ir.js";
4
5
  import { BIGINT_T } from "../ir/ir.js";
5
6
  import { isJsSourceFile, isNodeTypesPath } from "./program.js";
@@ -32,6 +33,14 @@ export const ISLAND_AMBIENT_TYPES = [
32
33
  "ReadableStreamReadValueResult",
33
34
  "ReadableStreamReadDoneResult",
34
35
  ];
36
+ function isAmbientAbortHandleType(type, ctx) {
37
+ if (type.isUnionType())
38
+ return ts.constituentTypes(type).some((part) => isAmbientAbortHandleType(part, ctx));
39
+ const symbol = type.getSymbol();
40
+ return !!symbol &&
41
+ (symbol.name === "AbortSignal" || symbol.name === "AbortController") &&
42
+ ctx.checker.declarationsOf(symbol).some((d) => (ts.isInterfaceDeclaration(d) || ts.isClassDeclaration(d)) && ctx.isStdlibFile(d.getSourceFile()));
43
+ }
35
44
  /** node:util.parseArgs's public and @types/node helper type names. Values
36
45
  * behind this surface use the checked-dynamic tree; see mapTypeInner. */
37
46
  const PARSE_ARGS_DYN_TYPES = new Set([
@@ -368,165 +377,244 @@ export class UnionRegistry {
368
377
  }
369
378
  /** Human-readable rendering of an IrType for diagnostics (records expand to
370
379
  * their canonical field list, unions to their arms; `checker.typeToString`
371
- * can't — it never sees IR types). `seen` breaks recursive shapes/unions:
372
- * a back-reference renders as "..." instead of expanding forever. */
380
+ * can't — it never sees IR types). Bound the traversal as well as its output:
381
+ * cycle detection alone still expands a shared acyclic graph exponentially.
382
+ * The same budget covers every sibling, and deep wrapper chains truncate
383
+ * before exhausting the JS stack. Small types retain their full spelling. */
373
384
  export function formatIrType(t, shapes, unions, seen = new Set()) {
374
- switch (t.kind) {
375
- case "f64":
376
- return "number";
377
- case "string":
378
- return "string";
379
- case "bool":
380
- return "boolean";
381
- case "dyn":
382
- return "unknown";
383
- case "caught":
384
- // What tsc calls the binding; the fence messages carry the real story.
385
- return "unknown";
386
- case "void":
387
- return "void";
388
- case "undefinedT":
389
- return "undefined";
390
- case "nullT":
391
- return "null";
392
- case "array": {
393
- // Union/func elements need the parens TS syntax would ("(number |
394
- // string)[]" — without them the [] reads as binding to the last arm).
395
- const elem = formatIrType(t.elem, shapes, unions, seen);
396
- return t.elem.kind === "union" || t.elem.kind === "func" ? `(${elem})[]` : `${elem}[]`;
397
- }
398
- case "bytes":
399
- // The u8 kind reads as Uint8Array (Buffer maps here too — one
400
- // runtime representation; the message stays honest either way).
401
- return t.elem === "u8" ? "Uint8Array" : t.elem === "u32" ? "Uint32Array" : t.elem === "i32" ? "Int32Array" : t.elem === "f32" ? "Float32Array" : "Float64Array";
402
- case "map":
403
- return `Map<${formatIrType(t.key, shapes, unions, seen)}, ${formatIrType(t.value, shapes, unions, seen)}>`;
404
- case "set":
405
- return `Set<${formatIrType(t.elem, shapes, unions, seen)}>`;
406
- case "func":
407
- return `(${t.params.map((p) => formatIrType(p, shapes, unions, seen)).join(", ")}) => ${formatIrType(t.ret, shapes, unions, seen)}`;
408
- case "object":
409
- // Runtime-provided error classes carry '%'-prefixed IR names
410
- // ("%Error") so user classes can never collide; diagnostics show the
411
- // source-level name.
412
- return t.className.startsWith("%") ? t.className.slice(1) : t.className;
413
- case "classval":
414
- // The static side, in TS's own spelling.
415
- return `typeof ${t.className.startsWith("%") ? t.className.slice(1) : t.className}`;
416
- case "record": {
417
- const shape = shapes.get(t.shapeId);
418
- if (!shape)
419
- return `{ /* unknown shape ${t.shapeId} */ }`;
420
- if (seen.has(t.shapeId))
421
- return "..."; // the recursive knot
422
- seen.add(t.shapeId);
423
- try {
424
- if (shape.tuple) {
425
- const byIndex = [...shape.fields].sort((a, b) => Number(a.name) - Number(b.name));
426
- return `[${byIndex.map((f) => formatIrType(f.type, shapes, unions, seen)).join(", ")}]`;
427
- }
428
- const members = shape.fields.map((f) => {
429
- // Accessor slots print in TS's accessor spelling, not the
430
- // reserved '%'-field encoding.
431
- const slot = accessorSlotProp(f.name);
432
- if (slot && f.type.kind === "func") {
433
- return slot.kind === "get"
434
- ? `get ${slot.prop}(): ${formatIrType(f.type.ret, shapes, unions, seen)}`
435
- : `set ${slot.prop}(${formatIrType(f.type.params[0] ?? VOID, shapes, unions, seen)})`;
385
+ const maxLength = 4096;
386
+ const maxDepth = 32;
387
+ let output = "";
388
+ let truncated = false;
389
+ const append = (text) => {
390
+ if (truncated)
391
+ return;
392
+ // Reserve the marker so a full buffer can always report truncation.
393
+ const remaining = maxLength - 3 - output.length;
394
+ if (text.length > remaining) {
395
+ output += text.slice(0, remaining) + "...";
396
+ truncated = true;
397
+ }
398
+ else {
399
+ output += text;
400
+ }
401
+ };
402
+ const list = (types, separator, depth) => {
403
+ for (let i = 0; i < types.length && !truncated; i++) {
404
+ if (i > 0)
405
+ append(separator);
406
+ visit(types[i], depth);
407
+ }
408
+ };
409
+ const visit = (t, depth) => {
410
+ if (truncated)
411
+ return;
412
+ if (depth >= maxDepth)
413
+ return append("...");
414
+ const child = (type) => visit(type, depth + 1);
415
+ switch (t.kind) {
416
+ case "f64":
417
+ return append("number");
418
+ case "string":
419
+ return append("string");
420
+ case "bool":
421
+ return append("boolean");
422
+ case "dyn":
423
+ return append("unknown");
424
+ case "caught":
425
+ // What tsc calls the binding; the fence messages carry the real story.
426
+ return append("unknown");
427
+ case "void":
428
+ return append("void");
429
+ case "undefinedT":
430
+ return append("undefined");
431
+ case "nullT":
432
+ return append("null");
433
+ case "array": {
434
+ // Union/func elements need the parens TS syntax would ("(number |
435
+ // string)[]" — without them the [] reads as binding to the last arm).
436
+ const parens = t.elem.kind === "union" || t.elem.kind === "func";
437
+ if (parens)
438
+ append("(");
439
+ child(t.elem);
440
+ return append(parens ? ")[]" : "[]");
441
+ }
442
+ case "bytes":
443
+ // The u8 kind reads as Uint8Array (Buffer maps here too — one
444
+ // runtime representation; the message stays honest either way).
445
+ return append(t.elem === "u8" ? "Uint8Array" : t.elem === "u32" ? "Uint32Array" : t.elem === "i32" ? "Int32Array" : t.elem === "f32" ? "Float32Array" : "Float64Array");
446
+ case "map":
447
+ append("Map<");
448
+ child(t.key);
449
+ append(", ");
450
+ child(t.value);
451
+ return append(">");
452
+ case "set":
453
+ append("Set<");
454
+ child(t.elem);
455
+ return append(">");
456
+ case "func":
457
+ append("(");
458
+ list(t.params, ", ", depth + 1);
459
+ append(") => ");
460
+ return child(t.ret);
461
+ case "object":
462
+ // Runtime-provided error classes carry '%'-prefixed IR names
463
+ // ("%Error") so user classes can never collide; diagnostics show the
464
+ // source-level name.
465
+ return append(t.className.startsWith("%") ? t.className.slice(1) : t.className);
466
+ case "classval":
467
+ // The static side, in TS's own spelling.
468
+ append("typeof ");
469
+ return append(t.className.startsWith("%") ? t.className.slice(1) : t.className);
470
+ case "record": {
471
+ const shape = shapes.get(t.shapeId);
472
+ if (!shape)
473
+ return append(`{ /* unknown shape ${t.shapeId} */ }`);
474
+ if (seen.has(t.shapeId))
475
+ return append("..."); // the recursive knot
476
+ seen.add(t.shapeId);
477
+ try {
478
+ if (shape.tuple) {
479
+ const byIndex = [...shape.fields].sort((a, b) => Number(a.name) - Number(b.name));
480
+ append("[");
481
+ for (let i = 0; i < byIndex.length && !truncated; i++) {
482
+ if (i > 0)
483
+ append(", ");
484
+ child(byIndex[i].type);
485
+ }
486
+ return append("]");
487
+ }
488
+ if (shape.fields.length === 0 && !shape.indexValue)
489
+ return append("{}");
490
+ append("{ ");
491
+ for (let i = 0; i < shape.fields.length && !truncated; i++) {
492
+ if (i > 0)
493
+ append("; ");
494
+ const f = shape.fields[i];
495
+ // Accessor slots print in TS's accessor spelling, not the
496
+ // reserved '%'-field encoding.
497
+ const slot = accessorSlotProp(f.name);
498
+ if (slot && f.type.kind === "func") {
499
+ append(slot.kind === "get" ? "get " : "set ");
500
+ append(slot.prop);
501
+ if (slot.kind === "get") {
502
+ append("(): ");
503
+ child(f.type.ret);
504
+ }
505
+ else {
506
+ append("(");
507
+ child(f.type.params[0] ?? VOID);
508
+ append(")");
509
+ }
510
+ }
511
+ else {
512
+ append(f.name);
513
+ append(": ");
514
+ child(f.type);
515
+ }
516
+ }
517
+ if (shape.indexValue) {
518
+ if (shape.fields.length > 0)
519
+ append("; ");
520
+ append("[key: string]: ");
521
+ child(shape.indexValue);
436
522
  }
437
- return `${f.name}: ${formatIrType(f.type, shapes, unions, seen)}`;
438
- });
439
- if (shape.indexValue) {
440
- members.push(`[key: string]: ${formatIrType(shape.indexValue, shapes, unions, seen)}`);
523
+ return append(" }");
524
+ }
525
+ finally {
526
+ seen.delete(t.shapeId); // sibling occurrences still expand
441
527
  }
442
- if (members.length === 0)
443
- return "{}";
444
- return `{ ${members.join("; ")} }`;
445
- }
446
- finally {
447
- seen.delete(t.shapeId); // sibling occurrences still expand
448
528
  }
449
- }
450
- case "union": {
451
- const def = unions.get(t.unionId);
452
- if (!def)
453
- return `/* union ${t.unionId} */`;
454
- if (seen.has(t.unionId))
455
- return "..."; // the recursive knot
456
- seen.add(t.unionId);
457
- try {
458
- return def.arms.map((a) => formatIrType(a, shapes, unions, seen)).join(" | ");
529
+ case "union": {
530
+ const def = unions.get(t.unionId);
531
+ if (!def)
532
+ return append(`/* union ${t.unionId} */`);
533
+ if (seen.has(t.unionId))
534
+ return append("..."); // the recursive knot
535
+ seen.add(t.unionId);
536
+ try {
537
+ return list(def.arms, " | ", depth + 1);
538
+ }
539
+ finally {
540
+ seen.delete(t.unionId);
541
+ }
459
542
  }
460
- finally {
461
- seen.delete(t.unionId);
543
+ case "jsval":
544
+ return append("any");
545
+ case "regex":
546
+ return append("RegExp");
547
+ case "date":
548
+ return append("Date");
549
+ case "url":
550
+ return append("URL");
551
+ case "searchParams":
552
+ return append("URLSearchParams");
553
+ case "symbol":
554
+ return append("symbol");
555
+ case "bigint":
556
+ return append("bigint");
557
+ case "stats":
558
+ return append("Stats");
559
+ case "fileHandle":
560
+ return append("FileHandle");
561
+ case "spawnRes":
562
+ return append("SpawnSyncReturns");
563
+ case "child":
564
+ return append("ChildProcess");
565
+ case "netServer":
566
+ return append("Server");
567
+ case "netSocket":
568
+ return append("Socket");
569
+ case "http2Session":
570
+ return append("Http2Session");
571
+ case "http2Stream":
572
+ return append("Http2Stream");
573
+ case "dgramSocket":
574
+ return append("dgram.Socket");
575
+ case "testCtx":
576
+ return append("TestContext");
577
+ case "httpReq":
578
+ return append("IncomingMessage");
579
+ case "httpRes":
580
+ return append("ServerResponse");
581
+ case "httpClientReq":
582
+ return append("ClientRequest");
583
+ case "secureCtx":
584
+ return append("SecureContext");
585
+ case "cryptoHash":
586
+ return append("Hash");
587
+ case "cryptoHmac":
588
+ return append("Hmac");
589
+ case "fsWatcher":
590
+ return append("FSWatcher");
591
+ case "childStream":
592
+ return append("Readable");
593
+ case "childWriter":
594
+ return append("Writable");
595
+ case "procStream":
596
+ return append("WriteStream");
597
+ case "moduleNs":
598
+ append("module namespace '");
599
+ append(t.moduleId);
600
+ return append("'");
601
+ case "promise":
602
+ append("Promise<");
603
+ child(t.inner);
604
+ return append(">");
605
+ case "generator":
606
+ append(t.async ? "AsyncGenerator<" : "Generator<");
607
+ list([t.yieldT, t.retT, t.nextT], ", ", depth + 1);
608
+ return append(">");
609
+ default: {
610
+ const _exhaustive = t;
611
+ void _exhaustive;
612
+ throw new InternalCompilerError("unreachable");
462
613
  }
463
614
  }
464
- case "jsval":
465
- return "any";
466
- case "regex":
467
- return "RegExp";
468
- case "date":
469
- return "Date";
470
- case "url":
471
- return "URL";
472
- case "searchParams":
473
- return "URLSearchParams";
474
- case "symbol":
475
- return "symbol";
476
- case "bigint":
477
- return "bigint";
478
- case "stats":
479
- return "Stats";
480
- case "fileHandle":
481
- return "FileHandle";
482
- case "spawnRes":
483
- return "SpawnSyncReturns";
484
- case "child":
485
- return "ChildProcess";
486
- case "netServer":
487
- return "Server";
488
- case "netSocket":
489
- return "Socket";
490
- case "http2Session":
491
- return "Http2Session";
492
- case "http2Stream":
493
- return "Http2Stream";
494
- case "dgramSocket":
495
- return "dgram.Socket";
496
- case "testCtx":
497
- return "TestContext";
498
- case "httpReq":
499
- return "IncomingMessage";
500
- case "httpRes":
501
- return "ServerResponse";
502
- case "httpClientReq":
503
- return "ClientRequest";
504
- case "secureCtx":
505
- return "SecureContext";
506
- case "cryptoHash":
507
- return "Hash";
508
- case "cryptoHmac":
509
- return "Hmac";
510
- case "fsWatcher":
511
- return "FSWatcher";
512
- case "childStream":
513
- return "Readable";
514
- case "childWriter":
515
- return "Writable";
516
- case "procStream":
517
- return "WriteStream";
518
- case "moduleNs":
519
- return `module namespace '${t.moduleId}'`;
520
- case "promise":
521
- return `Promise<${formatIrType(t.inner, shapes, unions, seen)}>`;
522
- case "generator":
523
- return `${t.async ? "AsyncGenerator" : "Generator"}<${formatIrType(t.yieldT, shapes, unions, seen)}, ${formatIrType(t.retT, shapes, unions, seen)}, ${formatIrType(t.nextT, shapes, unions, seen)}>`;
524
- default: {
525
- const _exhaustive = t;
526
- void _exhaustive;
527
- throw new InternalCompilerError("unreachable");
528
- }
529
- }
615
+ };
616
+ visit(t, 0);
617
+ return output;
530
618
  }
531
619
  /** True when the declaration sits inside `declare module "<name>"` (or
532
620
  * its node:-prefixed twin) — the disambiguator for builtin-module type
@@ -602,28 +690,6 @@ export function containsUnion(t) {
602
690
  return false;
603
691
  }
604
692
  }
605
- /** lower-calls.ts's bodyReadsArguments, duplicated here (type-mapper.ts must not
606
- * import from lowering/ — that edge is a module cycle): does the function's
607
- * OWN body read `arguments`? Nested plain functions/methods own theirs
608
- * (skipped); arrows see the enclosing one (descended). */
609
- function bodyReadsArgumentsLocal(fn) {
610
- let found = false;
611
- if (fn.body === undefined)
612
- return false;
613
- // Iterative walk (walkPreorder): function bodies can hold pathologically
614
- // deep expression chains that a recursive visit would die on.
615
- ts.walkPreorder(fn.body, (n) => {
616
- if (ts.isIdentifier(n) && n.text === "arguments" && !(ts.isPropertyAccessExpression(n.parent) && n.parent.name === n)) {
617
- found = true;
618
- return "stop";
619
- }
620
- if ((ts.isFunctionExpression(n) || ts.isFunctionDeclaration(n) || ts.isMethodDeclaration(n)) && n !== fn) {
621
- return "skip"; // own `arguments` scope
622
- }
623
- return undefined;
624
- });
625
- return found;
626
- }
627
693
  /** A generator type's normalized value channels (Generator<T, TReturn,
628
694
  * TNext> and the IteratorResult alias share this):
629
695
  * - yield: `never` (a generator that never yields) rides the VOID
@@ -1084,8 +1150,8 @@ function mapTypeInner(type, ctx) {
1084
1150
  // plumbing, values arrive dyn or convert via dynFrom.
1085
1151
  if (!et || et.kind === "void")
1086
1152
  return null;
1087
- // A jsval MEMBER absorbs the tuple (bare jsval fields have no shape
1088
- // slot — the record-field rule), exactly like record fields below.
1153
+ // A jsval member keeps this tuple in the island as a real JS array.
1154
+ // Object records may instead keep ambient abort handles in slots.
1089
1155
  if (et.kind === "jsval")
1090
1156
  return JSVAL;
1091
1157
  fields.push({ name: String(i), type: et });
@@ -2228,7 +2294,7 @@ function mapTypeInner(type, ctx) {
2228
2294
  // tsgo never SYNTHESIZES that rest param into the inferred signature
2229
2295
  // (5.9.3 did — the count mismatch above was the whole detector
2230
2296
  // there), so the declaration's own body answers directly.
2231
- if (sigDecl !== undefined && ts.isFunctionLike(sigDecl) && bodyReadsArgumentsLocal(sigDecl)) {
2297
+ if (sigDecl !== undefined && ts.isFunctionLike(sigDecl) && bodyReadsArguments(sigDecl)) {
2232
2298
  return null;
2233
2299
  }
2234
2300
  }
@@ -3415,14 +3481,11 @@ function mapRecordTypeInner(widened, ctx) {
3415
3481
  // accessor dispatch, so the shape stays unmapped.
3416
3482
  if (accessorSlotProp(p.name) !== null)
3417
3483
  return null;
3418
- // A bare jsval FIELD absorbs the record: shapes have no handle slot
3419
- // (the IR forbids jsval fields — no JSON story), while an island
3420
- // OBJECT holds engine values natively — `{ model: gateway(id),
3421
- // prompt }` is one island object, built field by field (jsval
3422
- // members as the same handle, static members marshaled). jsval-
3423
- // BEARING composite fields (`content: any[]`) keep their static
3424
- // shape — the lift covers them.
3425
- if (pt.kind === "jsval")
3484
+ // Keep ambient abort handles in a native record slot under --dynamic:
3485
+ // an options record with `signal?: AbortSignal` must not turn its
3486
+ // unrelated static fields into island properties. Other bare jsval
3487
+ // fields still absorb the record into one island object.
3488
+ if (pt.kind === "jsval" && !(ctx.dynamic && isAmbientAbortHandleType(fieldTs, ctx)))
3426
3489
  return JSVAL;
3427
3490
  fields.push({ name: p.name, type: pt });
3428
3491
  }
@@ -3623,7 +3686,7 @@ export function describeComponentBlocker(widened, ctx) {
3623
3686
  if (sigDecl !== undefined &&
3624
3687
  ts.isFunctionLike(sigDecl) &&
3625
3688
  (sigDecl.parameters.length !== sig.getParameters().length ||
3626
- bodyReadsArgumentsLocal(sigDecl))) {
3689
+ bodyReadsArguments(sigDecl))) {
3627
3690
  return `the function shape is supported, but its signature is variadic ('arguments'-reading), and a compiled signature is fixed-arity`;
3628
3691
  }
3629
3692
  for (const p of sig.getParameters()) {